首页
社区
课程
招聘
[原创]巧脱Themida 1.8.2+
发表于: 2008-1-26 12:57 10187

[原创]巧脱Themida 1.8.2+

2008-1-26 12:57
10187

巧脱Themida 1.8.2+

这里首先解释下为什么能“巧”,因为,第一,这个程序用的保护比较少的,至少没有VM,第二,这个程序脚本过不去。。。

我们的目标程序是CKwowCrack,就是Antrix,国外开发的魔兽世界模拟器,然后国内某某人拿到源代码之后,自己修正一点东西,再加一点其它的东西,然后编译了一下,加个某壳,然后就变成了www[dot]sfwowchina[dot]com上面的收费版,然后呢,其它某人把它给PJ了,然后加上了我们看见的某版本Themida,然后发布了出来……

然后我们现在有什么呢?第一,我们可以从网上下载到其它同版本号的Antrix,所以OEP对于我们不构成威胁。并以此我们还很确定的得知,其运行开始前就需要载入其目录下的其它DLL,这点为我们切入Themida的盔甲提供了便利,因为未被Themida分析过的用户DLL是不可知的,不可确定的。

所以我们首先先运行一下这个程序,然后附加进入,然后我们发现了0401000处的真实字节是0x55,然后我们重来,运用某种方法使得Themida停在前面一点的地方,附加进入,然后F9。

7C921230 ntdll.DbgBreakPoint   CC              int3
7C921231                       C3              retn        我们现在在这里
7C921232                       8BFF            mov     edi, edi
7C921234                       90              nop

然后我们来思考一下。Themida对Kernel32、user32、advapi32三个Dll进行了重载,使得我们想在这三个Dll里面下断点变得很困难。不过我们可以对VirtualProtect反汇编看下。
7C801AD0 kernel32.VirtualPro>    8BFF          mov     edi, edi
7C801AD2                     /.  55            push    ebp
7C801AD3                     |.  8BEC          mov     ebp, esp
7C801AD5                     |.  FF75 14       push    dword ptr [ebp+14]               ; /pOldProtect
7C801AD8                     |.  FF75 10       push    dword ptr [ebp+10]               ; |NewProtect
7C801ADB                     |.  FF75 0C       push    dword ptr [ebp+C]                ; |Size
7C801ADE                     |.  FF75 08       push    dword ptr [ebp+8]                ; |Address
7C801AE1                     |.  6A FF         push    -1                               ; |hProcess = FFFFFFFF
7C801AE3                     |.  E8 75FFFFFF   call    VirtualProtectEx                 ; 这里进入\VirtualProtectEx
7C801AE8                     |.  5D            pop     ebp
7C801AE9                     \.  C2 1000       retn    10

7C801A5D kernel32.VirtualPro>/$  8BFF          mov     edi, edi
7C801A5F                     |.  55            push    ebp
7C801A60                     |.  8BEC          mov     ebp, esp
7C801A62                     |.  56            push    esi
7C801A63                     |.  8B35 B812807C mov     esi, dword ptr [<&ntdll.NtProtec>;  ntdll.ZwProtectVirtualMemory
7C801A69                     |.  57            push    edi
7C801A6A                     |.  FF75 18       push    dword ptr [ebp+18]
7C801A6D                     |.  8D45 10       lea     eax, dword ptr [ebp+10]
7C801A70                     |.  FF75 14       push    dword ptr [ebp+14]
7C801A73                     |.  50            push    eax
7C801A74                     |.  8D45 0C       lea     eax, dword ptr [ebp+C]
7C801A77                     |.  50            push    eax
7C801A78                     |.  FF75 08       push    dword ptr [ebp+8]
7C801A7B                     |.  FFD6          call    esi            ;  <&ntdll.NtProtectVirtualMemory>
7C801A7D                     |.  8BF8          mov     edi, eax

7C92DEB6 ntdll.ZwProtectVirt>  B8 89000000     mov     eax, 89
7C92DEBB                       BA 0003FE7F     mov     edx, 7FFE0300
7C92DEC0                       FF12            call    dword ptr [edx]
7C92DEC2                       C2 1400         retn    14

到这里我们发现了一点什么,第一ZwProtectVirtualMemory这个函数位于Ntdll中,Themida没有偷到这边,第二其实他也不能偷,因为Kernel32队这边的调用是内存地址性的,再者这段函数搬到用户代码里面去根本就不会执行。

所以我们对ZwProtectVirtualMemory下断,这里你可以在每次断在这边的时候都看下0401000的数据,也可以下一个条件断点:byte [0401000]==55,然后F9,很快的我们就断下了。然后我们取消断点,没用了。

然后我们打开内存视图看下。
Memory map
地址=00400000        大小=00001000 (4096.)                PE Header
地址=00401000        大小=00499000 (4820992.)        Code+Data+IAT+...
地址=0089A000        大小=00001000 (4096.)                rsrc
在下面两个是Themida的杰作,我们就不看了。

地址=033D0000        大小=00001000 (4096.)
地址=034DE000        大小=00002000 (8192.)
这里我们注意到Private内存的界限在这边,然后我们对0401000段下内存写入断点。

00CA3157          890B            mov     dword ptr [ebx], ecx             ; 我们断在了这里
00CA3159          5B              pop     ebx

此时的寄存器:
EAX 007B75C8 antrix.007B75C8
ECX 71A24519 WS2_32.ioctlsocket
EDX 0000000A
EBX 007B75C8 antrix.007B75C8
ESP 0012FF74
EBP F78569DB
ESI 00C35047 antrix.00C35047
EDI 71A24519 WS2_32.ioctlsocket
EIP 00CA3157 antrix.00CA3157

我们看见了API,不过貌似没有加密,说明Themida对这个Dll放了水。
然后这条指令的目标内存是007B75C8,这里我们可以在内存窗口中移动到这里,按照win32的页面对齐,我相信我们会在007B7000这边发现点什么。

然后我们再来看一下内存视图。
Memory map, 条目 119
地址=034F0000         大小=00002000 (8192.)
地址=03500000         大小=00010000 (65536.)
地址=03510000         大小=00001000 (4096.)

我们发现多出来了这么几行,至于这几段内存是做什么的,大家可以自己下内存断点去看,我们直接用结论了。对0x034F0000段内存下写入断点。
00CA2B18          F3:A4           rep     movs byte ptr es:[edi], byte ptr>        ;We Are Here...
00CA2B1A          0F83 04000000   jnb     00CA2B24
00CA2B20          60              pushad
00CA2B21          B6 65           mov     dh, 65
00CA2B23          61              popad
00CA2B24        ^ E9 F5FCFFFF     jmp     00CA281E        ;这里似乎很想往上面跳,为什么我这么感觉是循环呢……

来看看寄存器:
EAX 00000000
ECX 00000002
EDX 5ADFD735
EBX 00BEC0F4 antrix.00BEC0F4
ESP 0012FF78
EBP F78569DB
ESI 7C8126F2 kernel32.PostQueuedCompletionStatus        ;我们看见了Api。。。。
EDI 034F0000
EIP 00CA2B18 antrix.00CA2B18

我们把Esi的值现抄下来。然后我们删除内存断点跳上去:
00CA2810         /0F8B 08000000   jpo     00CA281E
00CA2816         |0F8E 02000000   jle     00CA281E
00CA281C         |60              pushad
00CA281D         |61              popad
00CA281E         \803E E8         cmp     byte ptr [esi], 0E8        ;到了这里
00CA2821          0F85 EE000000   jnz     00CA2915

什么指令的Opcode是0xE8呢?call指令,下面我们就不看了,我们比较关心上面,就是循环前面的代码,因为我们不能每次都在循环里面转上半天才认识我们应该怎么做。我们看下上面的代码,我认为比较好的断点位置在00CA2810,然后我就华丽的下了断点。断下后我们看内存窗口。
007B7000  00000000  ....
007B7004  00000000  ....
007B7008  00000000  ....
007B700C  00000000  ....
007B7010  00000000  ....
007B7014  03520000  ..R        ;这里
007B7018  00000000  ....
007B701C  00000000  ....
007B7020  00000000  ....
007B7024  00000000  ....

我们去3520000看看。
03520000          8BFF            mov     edi, edi
.........
03520255          FF15 1012807C   call    dword ptr [<&ntdll.NtSetIoComple>; ntdll.ZwSetIoCompletion

看到这里我想起了什么,于是将3520255的指令在Kernel32种搜索了一下。发现了一个唯一的结果:
7C8126F2 k>    8BFF          mov     edi, edi        ;kernel32.PostQueuedCompletionStatus
7C8126F4    .  55            push    ebp
7C8126F5    .  8BEC          mov     ebp, esp
7C8126F7    .  56            push    esi
7C8126F8    .  FF75 0C       push    dword ptr [ebp+C]
7C8126FB    .  33F6          xor     esi, esi
7C8126FD    .  6A 00         push    0
7C8126FF    .  FF75 14       push    dword ptr [ebp+14]
7C812702    .  46            inc     esi
7C812703    .  FF75 10       push    dword ptr [ebp+10]
7C812706    .  FF75 08       push    dword ptr [ebp+8]
7C812709    .  FF15 1012807C call    dword ptr [<&ntdll.NtSetIoComple>;  ntdll.ZwSetIoCompletion
7C81270F    .  85C0          test    eax, eax
7C812711    .  0F8C D4A00200 jl      7C83C7EB
7C812717    >  8BC6          mov     eax, esi
7C812719    .  5E            pop     esi
7C81271A    .  5D            pop     ebp
7C81271B    .  C2 1000       retn    10

我们似乎理解到了什么。于是把7b7020处的数值修正为7C8126F2,于是我们似乎解决了什么。然后我们进入手工循环……
很可惜的是,我在修完kernel32和user32之后程序退出了。然后我们正常的到达OEP,然后我们就剩4个advapi的了。
然后手动修一下,拿出ImportRec保存下,我们就有了正确的IAT了。

然后我们重来,修理下另外一样东西。
我们接着00CA3157          890B            mov     dword ptr [ebx], ecx  这里继续往下单步,然后发现了这里:
00CA346C    803F 90         cmp     byte ptr [edi], 90              
00CA346F    0F84 3D000000   je      00CA34B2                        

我们看下Edi的地方
0066B520    55              push    ebp
0066B521    8BEC            mov     ebp, esp
0066B523    51              push    ecx
0066B524    C745 FC 0100000>mov     dword ptr [ebp-4], 1
0066B52B    8D45 FC         lea     eax, dword ptr [ebp-4]
0066B52E    50              push    eax
0066B52F    68 7E660480     push    8004667E
0066B534    8B4D 08         mov     ecx, dword ptr [ebp+8]
0066B537    51              push    ecx
0066B538    90              nop                <-这里
0066B539    90              nop
0066B53A    90              nop
0066B53B    90              nop
0066B53C    90              nop
0066B53D    90              nop
0066B53E    F7D8            neg     eax
0066B540    1BC0            sbb     eax, eax
0066B542    40              inc     eax
0066B543    8BE5            mov     esp, ebp
0066B545    5D              pop     ebp
0066B546    C3              retn

我们来想下什么指令是6字节的,Call [imm32],Jmp [Imm32]。

然后我们知道了什么,我们继续走到了被偷过的OEP。然后我们补上OEP之后DUMP。我们得到了一个文件,很显然这个文件并不能运行。
(由于下一步我还没完成,主要是最近太懒。我说下思路吧,应该会正确的)
我们写个小程序,载入代码段,然后枚举0xE8和0xE9,然后只要判断这个目标地址是不是在IAT区间中存在,存在的话则为需要修复的,然后再确定指令前是不是0x90,然后就可以正确的进行Patch,然后收工……


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (8)
雪    币: 223
活跃值: (70)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
源码交出来。。
2008-1-26 14:08
0
雪    币: 485
活跃值: (12)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
3
占座学习。。。。
2008-1-26 14:10
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
太多了.........不明白.....
2008-1-26 23:34
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
.................领教了.................
2008-1-27 21:46
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
楼主发的另一网络验证【难】的帖子应该好解决,多看看黑鹰VIP破解教程还有天草的视频教程
2008-1-28 14:54
0
雪    币: 622
活跃值: (294)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
7
楼上的某位,能说下是什么帖子么,我怎么不记得了。。
2008-1-28 17:02
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
精彩  学习了 刚刚好有 个这个的壳等我去搞
2008-2-7 20:54
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
还是不太懂..
2008-4-26 05:34
0
游客
登录 | 注册 方可回帖
返回
//