wuhanqi 发表于 2009-8-10 09:57

【原创】简单修复Themida加壳的VC7+去除软件自校验

【文章标题】: 简单修复Themida加壳的VC7+去除软件自校验
【文章作者】: wuhanqi
【作者邮箱】: wuhanqi@qq.com
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
题外话:
   其实这个VC7的程序我本来都放一边了,因为实在是找不到对比OEP的无壳程序,可是昨天Nisy 老大发给我一个蛮有意思的注册验证程序,DJ Java Decompiler 3.11,无壳的,我用OD载入后一看到Push 60就一下子想起了这个TMD加壳的VC7,遂有了此文。

加壳程序是国产的。我就不透漏名称了。

这就是无壳程序的OEP:
00477F88 > $6A 60         PUSH 60
00477F8A   .68 30805000   PUSH 00508030
00477F8F   .E8 744D0000   CALL 0047CD08
00477F94   .BF 94000000   MOV EDI,94
00477F99   .8BC7          MOV EAX,EDI
00477F9B   .E8 70FEFFFF   CALL 00477E10
00477FA0   .8965 E8       MOV DWORD PTR SS:,ESP
00477FA3   .8BF4          MOV ESI,ESP
00477FA5   .893E          MOV DWORD PTR DS:,EDI
00477FA7   .56            PUSH ESI                                 ; /pVersionInformation
00477FA8   .FF15 78934F00 CALL DWORD PTR DS:[<&KERNEL32.GetVersion>; \GetVersionExA
00477FAE   .8B4E 10       MOV ECX,DWORD PTR DS:
00477FB1   .890D CC465400 MOV DWORD PTR DS:,ECX
00477FB7   .8B46 04       MOV EAX,DWORD PTR DS:
00477FBA   .A3 D8465400   MOV DWORD PTR DS:,EAX
00477FBF   .8B56 08       MOV EDX,DWORD PTR DS:
00477FC2   .8915 DC465400 MOV DWORD PTR DS:,EDX
00477FC8   .8B76 0C       MOV ESI,DWORD PTR DS:
00477FCB   .81E6 FF7F0000 AND ESI,7FFF
00477FD1   .8935 D0465400 MOV DWORD PTR DS:,ESI
00477FD7   .83F9 02       CMP ECX,2
00477FDA   .74 0C         JE SHORT 00477FE8
00477FDC   .81CE 00800000 OR ESI,8000
00477FE2   .8935 D0465400 MOV DWORD PTR DS:,ESI
00477FE8   >C1E0 08       SHL EAX,8
00477FEB   .03C2          ADD EAX,EDX
00477FED   .A3 D4465400   MOV DWORD PTR DS:,EAX
00477FF2   .33F6          XOR ESI,ESI
00477FF4   .56            PUSH ESI                                 ; /pModule => NULL
00477FF5   .8B3D 5C934F00 MOV EDI,DWORD PTR DS:[<&KERNEL32.GetModu>; |kernel32.GetModuleHandleA
00477FFB   .FFD7          CALL EDI                                 ; \GetModuleHandleA
00477FFD   .66:8138 4D5ACMP WORD PTR DS:,5A4D
00478002   .75 1F         JNZ SHORT 00478023


废话不多说了,OD载入程序打开内存镜像看TMDBASE是多少,565000,用编辑工具修改一下Nooby牛的脚本,然后跑脚本...这个过程我就不多叙述了。
脚本结束后停在OEP附近的第一个CALL中。
00471940    68 A0F14600   push 0046F1A0
00471945    64:A1 00000000mov eax,dword ptr fs:
0047194B    50            push eax
0047194C    8B4424 10       mov eax,dword ptr ss:
00471950    896C24 10       mov dword ptr ss:,ebp
00471954    8D6C24 10       lea ebp,dword ptr ss:
00471958    2BE0            sub esp,eax
0047195A    53            push ebx
0047195B    56            push esi
0047195C    57            push edi
0047195D    8B45 F8         mov eax,dword ptr ss:
00471960    8965 E8         mov dword ptr ss:,esp
00471963    50            push eax
00471964    8B45 FC         mov eax,dword ptr ss:
00471967    C745 FC FFFFFFF>mov dword ptr ss:,-1
0047196E    8945 F8         mov dword ptr ss:,eax
00471971    8D45 F0         lea eax,dword ptr ss:
00471974    64:A3 00000000mov dword ptr fs:,eax
0047197A    C3            retn

看堆栈:
0012FF54   007FE908SuperRec.007FE908
0012FF58   0049F740SuperRec.0049F740第②句PUSH
0012FF5C   00000060                     第①句PUSH
0012FF60   00400208ASCII "   "
0012FF64   0012FFC4
0012FF68   00792EB8SuperRec.00792EB8

可以猜出前三句OEP为
push 60
push 0049f740
call 00471940

接下来走出这个call。
007FE908    68 16EB2925   push 2529EB16
007FE90D^ E9 29B9FFFF   jmp 007FA23B

单步走过上面的jmp,来到:
007FA23B    6A 00         push 0
007FA23D    0F89 15000000   jns 007FA258

打开内存镜像。在00401000段F2,然后F9,停在OEP附近第二个call处。
00470540    3D 00100000   cmp eax,1000
00470545    73 0E         jnb short 00470555
00470547    F7D8            neg eax
00470549    03C4            add eax,esp
0047054B    83C0 04         add eax,4
0047054E    8500            test dword ptr ds:,eax
00470550    94            xchg eax,esp
00470551    8B00            mov eax,dword ptr ds:
00470553    50            push eax
00470554    C3            retn

此时可以对比无壳的程序看一下代码,这是无壳的前几句:
00477F88 > $6A 60         PUSH 60
00477F8A   .68 30805000   PUSH 00508030
00477F8F   .E8 744D0000   CALL 0047CD08
00477F94   .BF 94000000   MOV EDI,94
00477F99   .8BC7          MOV EAX,EDI
00477F9B   .E8 70FEFFFF   CALL 00477E10
00477FA0   .8965 E8       MOV DWORD PTR SS:,ESP

再看看我们的寄存器。
EAX 00000094
ECX 00020048
EDX 00020048
EBX 0012FF64
ESP 0012FEDC
EBP 0012FF5C
ESI F63945F1
EDI 00000094
EIP 00470540 SuperRec.00470540

的确EDI与EAX都变红而且都为94

那接下来三句就是
mov edi,94
mov eax,edi
call 00470540

接下来走出这个call:
007FE91A    68 7FE9110B   push 0B11E97F
007FE91F^ E9 17B9FFFF   jmp 007FA23B

依旧走过这个jmp后在code段下断再F9
此时停在这里:
019F8947    FF33            push dword ptr ds:                  ; kernel32.GetVersionExA
019F8949^ E9 F580F5FF   jmp 01950A43

看信息窗口:
ds:[004932AC]=77AB9D76 (kernel32.GetVersionExA)

这个地址很关键,我们可以对照着看无壳程序的OEP,在下一个call就是call这个函数,
那这个call就应该这样写了:call dword ptr ds:

又因为VC7的OEP相对固定,
那接下来几句就是:
MOV DWORD PTR SS:,ESP
MOV ESI,ESP
MOV DWORD PTR DS:,EDI
PUSH ESI   
call dword ptr ds:
   
插句题外话:其实你记不住这个地址也没问题,因为GetVersionExA和GetModuleHandleA在IAT输入表里很接近.而程序下面就就有调用GetModuleHandleA,找到了GetModuleHandleA就等于找到了GetVersionExA.

我们再继续走jmp下code段的断点。此过程我就不做记录了。
值的注意的是走到这里的时候:
019FD621    F3:A4         rep movs byte ptr es:,byte ptr ds:[>
019FD623    68 016D0000   push 6D01
019FD628    890C24          mov dword ptr ss:,ecx

在019fd621需要是F7再F8,否则程序跑飞,前功尽弃。
最终我们停在这里:
0046EF05    A3 00B65100   mov dword ptr ds:,eax
0046EF0A    8B56 08         mov edx,dword ptr ds:
0046EF0D    8915 04B65100   mov dword ptr ds:,edx
0046EF13    8B76 0C         mov esi,dword ptr ds:
0046EF16    81E6 FF7F0000   and esi,7FFF
0046EF1C    8935 F8B55100   mov dword ptr ds:,esi
0046EF22    83F9 02         cmp ecx,2
0046EF25    74 0C         je short 0046EF33
0046EF27    81CE 00800000   or esi,8000
0046EF2D    8935 F8B55100   mov dword ptr ds:,esi
0046EF33    C1E0 08         shl eax,8
0046EF36    03C2            add eax,edx
0046EF38    A3 FCB55100   mov dword ptr ds:,eax
0046EF3D    33F6            xor esi,esi
0046EF3F    56            push esi
0046EF40    8B3D A8324900   mov edi,dword ptr ds:            ; kernel32.GetModuleHandleA
0046EF46    FFD7            call edi
0046EF48    66:8138 4D5A    cmp word ptr ds:,5A4D

上面距离call GetVersionExA 这个函数依旧还有三句话:
这是无壳程序的那三句话:
00477FAE   .8B4E 10       MOV ECX,DWORD PTR DS:
00477FB1   .890D CC465400 MOV DWORD PTR DS:,ECX
00477FB7   .8B46 04       MOV EAX,DWORD PTR DS:
00477FBA   .A3 D8465400   MOV DWORD PTR DS:,EAX

这下有人晕了,这可怎么搞,没有地址怎么修复?
其实很简单,我们用无壳程序的这两句地址相减,即5446d8-5446cc=c
那我们需要的那个地址就应该是 51b600-c=51B5F4

那我们加壳程序的接下来三句就应该是:
MOV ECX,DWORD PTR DS:
MOV DWORD PTR DS:,ECX
MOV EAX,DWORD PTR DS:

总结一下被偷的OEP就是:
push 60
push 0049f740
call 00471940
mov edi,94
mov eax,edi
call 00470540
MOV DWORD PTR SS:,ESP
MOV ESI,ESP
MOV DWORD PTR DS:,EDI
PUSH ESI   
call dword ptr ds:
MOV ECX,DWORD PTR DS:
MOV DWORD PTR DS:,ECX
MOV EAX,DWORD PTR DS:   

这样脱好壳之后,运行程序,窗口一闪而过。
自校验。。
我用的是bp GetFileSize
因为程序是窗口一闪而过,所以要在显示窗口后再返回程序。
返回程序领空只需要F8即可来到这里:
0042A126   > \3B7424 20   cmp esi,dword ptr ss:
0042A12A   .74 14         je short 0042A140
0042A12C   .8B5424 24   mov edx,dword ptr ss:
0042A130   .8B42 2C       mov eax,dword ptr ds:
0042A133   .53            push ebx                                 ; /lParam
0042A134   .53            push ebx                                 ; |wParam
0042A135   .6A 12         push 12                                  ; |Message = WM_QUIT
0042A137   .50            push eax                                 ; |ThreadId
0042A138   .90            nop                                    ; |
0042A139   .E8 50DB1877   call user32.PostThreadMessageW         ; \PostThreadMessageW
0042A13E   .EB 15         jmp short 0042A155
0042A140   >57            push edi
0042A141   .E8 FC580500   call 0047FA42
0042A146   .8B8D 68AB0200 mov ecx,dword ptr ss:
0042A14C   .83C4 04       add esp,4
0042A14F   .C701 08000000 mov dword ptr ds:,8
0042A155   >8D4C24 28   lea ecx,dword ptr ss:
0042A159   .885C24 40   mov byte ptr ss:,bl
0042A15D   .E8 6A700500   call 004811CC
0042A162   .5D            pop ebp

把42a12a的74改成eb即可。
第一次看到结束程序用PostThreadMessageW的这个函数的。。

--------------------------------------------------------------------------------
【经验总结】
其实VC7的OEP真的很好修复的.不是一般的好修复.
只不过很难找到一个门当户对的无壳程序来对比OEP修复.
这次是我运气好,也感谢Nisy老大~呵呵.

--------------------------------------------------------------------------------
【版权声明】: 菜鸟一个,没啥版权..

                                                       2009年08月10日 8:59:29

mantoou 发表于 2009-8-10 16:31

楼主能把脚本提供下么,谢谢啦

小生我怕怕 发表于 2009-8-11 02:45

不错,好文才,学习下~

wgz001 发表于 2009-8-11 07:35

精品文章   :victory:

ZeNiX 发表于 2009-8-11 10:34

依据特征碼來猜 OEP 及修復.
很經典的做法.

學習下~~

jordanpz 发表于 2009-8-13 13:29

5# zenix


问下,楼主用的nooby 脚本在哪下载?

假面泰山 发表于 2009-8-13 14:28

虚心学习下 楼主辛苦了。。大家一起努力。

84489235 发表于 2009-8-13 14:47

ddddddddddddd

kelvar 发表于 2009-8-15 12:49

修复一块学到不少东西。顺便问下Nisy老大还在做什么教学?

wuhanqi 发表于 2009-8-15 15:12

16位平台下的C,这是最近的了
页: [1] 2
查看完整版本: 【原创】简单修复Themida加壳的VC7+去除软件自校验