用WinDbg动态脱Reflector

Bi11[CCG]
4 Feb 2006

我才知道WinDbg+SOS能调托管程序。。。无敌。。。

举个例子吧,脱Reflector玩玩,最新的4.2.0.0。
精华7里henryouly的《研读Reflector的保护原理心得》文中已经说了原理。简单说就是先解压,然后用Assembly.Load(byte[])加载。这次我们的任务是动态将这个要加载的byte[]给dump出来。

用WinDbg加载Reflector
Microsoft (R) Windows Debugger  Version 6.6.0003.5
...

在加载mscorjit.dll时设异常,执行
0:000> sxe ld:mscorjit.dll
0:000> g
...
ModLoad: 79430000 7947d000   C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\MSCORJIT.DLL
eax=00000000 ebx=00000000 ecx=00f60000 edx=7c92eb94 esi=00000000 edi=00000000
eip=7c92eb94 esp=0012e99c ebp=0012ea90 iopl=0         nv up ei ng nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000296
ntdll!KiFastSystemCallRet:
7c92eb94 c3               ret

载入sos.dll (WinDbg的插件,就在%windir%\Microsoft.NET\Framework\v1.1.4322\下。如果不能加载,请先设PATH环境变量)
0:000> .load sos

找Assembly.Load的MethodDesc
0:000> !name2ee mscorlib.dll System.Reflection.Assembly.Load
Loaded Son of Strike data table version 5 from "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\mscorwks.dll"
...
-----------------------
MethodDesc: 79ba35a8
Name: [DEFAULT] Class System.Reflection.Assembly System.Reflection.Assembly.Load(SZArray UI1)
-----------------------

给这个MethodDesc的m_CodeOrIL上加个断点(等RV添入)
0:000> ba w4 79ba35a8+4
0:000> g
Breakpoint 0 hit
...

RV应该添入了,设个断点
0:000> bp poi(79ba35a8+4)
0:000> g
Breakpoint 1 hit
eax=79a3bea8 ebx=01283de0 ecx=02447a68 edx=00b4568c esi=01285f54 edi=01285f30
eip=79a3bea8 esp=0012f644 ebp=0012f674 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mscorlib_79990000+0xabea8:
79a3bea8 50               push    eax

看看堆栈,没问题~
0:000> !clrstack
Thread 0
ESP       EIP     
0012f644  79a3bea8 [DEFAULT] Class System.Reflection.Assembly System.Reflection.Assembly.Load(SZArray UI1)
0012f648  00f702d7 [DEFAULT] [hasThis] Void Reflector.Application..ctor(Class Reflector.IWindowManager)
0012f67c  00f70090 [DEFAULT] Void Reflector.Application.ᐁ()
0012f9b0  791d94bc [FRAME: GCFrame] 
0012fa94  791d94bc [FRAME: GCFrame] 

看看堆栈里的objects
0:000> !dumpstackobjects
ESP/REG  Object   Name
ebx      01283de0 Reflector.Application
ecx      02447a68 System.Byte[]
esi      01285f54 ᐄ
edi      01285f30 System.IO.MemoryStream
0012f64c 01283de0 Reflector.Application
0012f654 01284dec System.IO.__UnmanagedMemoryStream
0012f660 01283de0 Reflector.Application

我们找到了她的地址:2447a68,看看:
0:000> d 02447a68
02447a68  3c 2c b6 00 00 00 0e 00-4d 5a 00 00 05 00 00 00  <,......MZ......
02447a78  04 00 00 00 ff ff 00 00-80 00 00 00 00 00 00 00  ................
02447a88  40 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  @...............
02447a98  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
02447aa8  00 00 00 00 80 00 00 00-0e 1f e8 00 00 5a 83 c2  .............Z..
02447ab8  0d b4 09 cd 21 b8 01 4c-cd 21 54 68 69 73 20 70  ....!..L.!This p
02447ac8  72 6f 67 72 61 6d 20 63-61 6e 6e 6f 74 20 62 65  rogram cannot be
02447ad8  20 72 75 6e 20 69 6e 20-44 4f 53 20 6d 6f 64 65   run in DOS mode

换只眼看看
0:000> dd 02447a68
02447a68  00b62c3c 000e0000 00005a4d 00000005
02447a78  00000004 0000ffff 00000080 00000000
02447a88  00000040 00000000 00000000 00000000
02447a98  00000000 00000000 00000000 00000000
02447aa8  00000000 00000080 00e81f0e c2835a00
02447ab8  cd09b40d 4c01b821 685421cd 70207369
02447ac8  72676f72 63206d61 6f6e6e61 65622074
02447ad8  6e757220 206e6920 20534f44 65646f6d

用LordPE把0x2447a70开始,0xe0000大小的内存Dump到文件。改个exe,peid查看入口,_CorDllMain,是dll文件。那就再把文件名改成dll。

拖到Reflector,正常,收工。初次玩WinDbg,有出丑的地方还请指正~

顺便提一下,4.2的Reflector混淆用的都是不可显示的Unicode,出来一个个框框,太有创意了。


主要参考资料:

在托管代码中设置断点(WINDBG) 
http://blog.joycode.com/gangp/articles/20417.aspx

用WinDbg探索CLR世界 [3] 跟踪方法的 JIT 过程
http://www.blogcn.com/User8/flier_lu/blog/1678453.html

SOS - Son of Strike
%???%\SDK\v1.1\Tool Developers Guide\Samples\sos\SOS.htm