| 
注册时间2007-1-1
阅读权限40
最后登录1970-1-1UID26439 独步武林  
 
 该用户从未签到 | 
 
| 【文章标题】: 简单修复Themida加壳的VC7+去除软件自校验 【文章作者】: wuhanqi
 【作者邮箱】: [email protected]
 【下载地址】: 自己搜索下载
 【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
 --------------------------------------------------------------------------------
 【详细过程】
 题外话:
 其实这个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:[EBP-18],ESP
 00477FA3   .  8BF4          MOV ESI,ESP
 00477FA5   .  893E          MOV DWORD PTR DS:[ESI],EDI
 00477FA7   .  56            PUSH ESI                                 ; /pVersionInformation
 00477FA8   .  FF15 78934F00 CALL DWORD PTR DS:[<&KERNEL32.GetVersion>; \GetVersionExA
 00477FAE   .  8B4E 10       MOV ECX,DWORD PTR DS:[ESI+10]
 00477FB1   .  890D CC465400 MOV DWORD PTR DS:[5446CC],ECX
 00477FB7   .  8B46 04       MOV EAX,DWORD PTR DS:[ESI+4]
 00477FBA   .  A3 D8465400   MOV DWORD PTR DS:[5446D8],EAX
 00477FBF   .  8B56 08       MOV EDX,DWORD PTR DS:[ESI+8]
 00477FC2   .  8915 DC465400 MOV DWORD PTR DS:[5446DC],EDX
 00477FC8   .  8B76 0C       MOV ESI,DWORD PTR DS:[ESI+C]
 00477FCB   .  81E6 FF7F0000 AND ESI,7FFF
 00477FD1   .  8935 D0465400 MOV DWORD PTR DS:[5446D0],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:[5446D0],ESI
 00477FE8   >  C1E0 08       SHL EAX,8
 00477FEB   .  03C2          ADD EAX,EDX
 00477FED   .  A3 D4465400   MOV DWORD PTR DS:[5446D4],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 4D5A  CMP WORD PTR DS:[EAX],5A4D
 00478002   .  75 1F         JNZ SHORT 00478023
 
 
 废话不多说了,OD载入程序打开内存镜像看TMDBASE是多少,565000,用编辑工具修改一下Nooby牛的脚本,然后跑脚本...这个过程我就不多叙述了。
 脚本结束后停在OEP附近的第一个CALL中。
 00471940    68 A0F14600     push 0046F1A0
 00471945    64:A1 00000000  mov eax,dword ptr fs:[0]
 0047194B    50              push eax
 0047194C    8B4424 10       mov eax,dword ptr ss:[esp+10]
 00471950    896C24 10       mov dword ptr ss:[esp+10],ebp
 00471954    8D6C24 10       lea ebp,dword ptr ss:[esp+10]
 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:[ebp-8]
 00471960    8965 E8         mov dword ptr ss:[ebp-18],esp
 00471963    50              push eax
 00471964    8B45 FC         mov eax,dword ptr ss:[ebp-4]
 00471967    C745 FC FFFFFFF>mov dword ptr ss:[ebp-4],-1
 0047196E    8945 F8         mov dword ptr ss:[ebp-8],eax
 00471971    8D45 F0         lea eax,dword ptr ss:[ebp-10]
 00471974    64:A3 00000000  mov dword ptr fs:[0],eax
 0047197A    C3              retn
 
 看堆栈:
 0012FF54   007FE908  SuperRec.007FE908
 0012FF58   0049F740  SuperRec.0049F740  第②句PUSH
 0012FF5C   00000060                     第①句PUSH
 0012FF60   00400208  ASCII "   "
 0012FF64   0012FFC4
 0012FF68   00792EB8  SuperRec.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],eax
 00470550    94              xchg eax,esp
 00470551    8B00            mov eax,dword ptr ds:[eax]
 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:[EBP-18],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:[ebx]                  ; kernel32.GetVersionExA
 019F8949  ^ E9 F580F5FF     jmp 01950A43
 
 看信息窗口:
 ds:[004932AC]=77AB9D76 (kernel32.GetVersionExA)
 
 这个地址很关键,我们可以对照着看无壳程序的OEP,在下一个call就是call这个函数,
 那这个call就应该这样写了:call dword ptr ds:[004932ac]
 
 又因为VC7的OEP相对固定,
 那接下来几句就是:
 MOV DWORD PTR SS:[EBP-18],ESP
 MOV ESI,ESP
 MOV DWORD PTR DS:[ESI],EDI
 PUSH ESI
 call dword ptr ds:[004932ac]
 
 插句题外话:其实你记不住这个地址也没问题,因为GetVersionExA和GetModuleHandleA在IAT输入表里很接近.而程序下面就就有调用GetModuleHandleA,找到了GetModuleHandleA就等于找到了GetVersionExA.
 
 我们再继续走jmp下code段的断点。此过程我就不做记录了。
 值的注意的是走到这里的时候:
 019FD621    F3:A4           rep movs byte ptr es:[edi],byte ptr ds:[>
 019FD623    68 016D0000     push 6D01
 019FD628    890C24          mov dword ptr ss:[esp],ecx
 
 在019fd621需要是F7再F8,否则程序跑飞,前功尽弃。
 最终我们停在这里:
 0046EF05    A3 00B65100     mov dword ptr ds:[51B600],eax
 0046EF0A    8B56 08         mov edx,dword ptr ds:[esi+8]
 0046EF0D    8915 04B65100   mov dword ptr ds:[51B604],edx
 0046EF13    8B76 0C         mov esi,dword ptr ds:[esi+C]
 0046EF16    81E6 FF7F0000   and esi,7FFF
 0046EF1C    8935 F8B55100   mov dword ptr ds:[51B5F8],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:[51B5F8],esi
 0046EF33    C1E0 08         shl eax,8
 0046EF36    03C2            add eax,edx
 0046EF38    A3 FCB55100     mov dword ptr ds:[51B5FC],eax
 0046EF3D    33F6            xor esi,esi
 0046EF3F    56              push esi
 0046EF40    8B3D A8324900   mov edi,dword ptr ds:[4932A8]            ; kernel32.GetModuleHandleA
 0046EF46    FFD7            call edi
 0046EF48    66:8138 4D5A    cmp word ptr ds:[eax],5A4D
 
 上面距离call GetVersionExA 这个函数依旧还有三句话:
 这是无壳程序的那三句话:
 00477FAE   .  8B4E 10       MOV ECX,DWORD PTR DS:[ESI+10]
 00477FB1   .  890D CC465400 MOV DWORD PTR DS:[5446CC],ECX
 00477FB7   .  8B46 04       MOV EAX,DWORD PTR DS:[ESI+4]
 00477FBA   .  A3 D8465400   MOV DWORD PTR DS:[5446D8],EAX
 
 这下有人晕了,这可怎么搞,没有地址怎么修复?
 其实很简单,我们用无壳程序的这两句地址相减,即5446d8-5446cc=c
 那我们需要的那个地址就应该是 51b600-c=51B5F4
 
 那我们加壳程序的接下来三句就应该是:
 MOV ECX,DWORD PTR DS:[ESI+10]
 MOV DWORD PTR DS:[51B5F4],ECX
 MOV EAX,DWORD PTR DS:[ESI+4]
 
 总结一下被偷的OEP就是:
 push 60
 push 0049f740
 call 00471940
 mov edi,94
 mov eax,edi
 call 00470540
 MOV DWORD PTR SS:[EBP-18],ESP
 MOV ESI,ESP
 MOV DWORD PTR DS:[ESI],EDI
 PUSH ESI
 call dword ptr ds:[004932ac]
 MOV ECX,DWORD PTR DS:[ESI+10]
 MOV DWORD PTR DS:[51B5F4],ECX
 MOV EAX,DWORD PTR DS:[ESI+4]
 
 这样脱好壳之后,运行程序,窗口一闪而过。
 自校验。。
 我用的是bp GetFileSize
 因为程序是窗口一闪而过,所以要在显示窗口后再返回程序。
 返回程序领空只需要F8即可来到这里:
 0042A126   > \3B7424 20     cmp esi,dword ptr ss:[esp+20]
 0042A12A   .  74 14         je short 0042A140
 0042A12C   .  8B5424 24     mov edx,dword ptr ss:[esp+24]
 0042A130   .  8B42 2C       mov eax,dword ptr ds:[edx+2C]
 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:[ebp+2AB68]
 0042A14C   .  83C4 04       add esp,4
 0042A14F   .  C701 08000000 mov dword ptr ds:[ecx],8
 0042A155   >  8D4C24 28     lea ecx,dword ptr ss:[esp+28]
 0042A159   .  885C24 40     mov byte ptr ss:[esp+40],bl
 0042A15D   .  E8 6A700500   call 004811CC
 0042A162   .  5D            pop ebp
 
 把42a12a的74改成eb即可。
 第一次看到结束程序用PostThreadMessageW的这个函数的。。
 
 --------------------------------------------------------------------------------
 【经验总结】
 其实VC7的OEP真的很好修复的.不是一般的好修复.
 只不过很难找到一个门当户对的无壳程序来对比OEP修复.
 这次是我运气好,也感谢Nisy老大~呵呵.
 
 --------------------------------------------------------------------------------
 【版权声明】: 菜鸟一个,没啥版权..
 
 2009年08月10日 8:59:29
 | 
 |