脱PECompact壳的总结

用PEid检测为:
PECompact 2.x -> Jeremy Collake
  
用OD载入:


  004010CC notepad.>  B8 48E84000      mov eax,notepad.0040E848
  004010D1            50               push eax
  004010D2            64:FF35 00000000 push dword ptr fs:[0]
  004010D9            64:8925 00000000 mov dword ptr fs:[0],esp
  004010E0            33C0             xor eax,eax

  
      一看到fs:[0],本能猜到壳用到了异常,决定先用ESP定律试试,F8单步到:
  004010D9            64:8925 00000000 mov dword ptr fs:[0],esp
  
     此时ESP=0013FFBC,下断:hr 0013FFBC,然后按Shift+F9,断下:


  0040E877            83C4 04          add esp,4
  0040E87A            55               push ebp
  0040E87B            53               push ebx
  0040E87C            51               push ecx
  0040E87D            57               push edi
  0040E87E            56               push esi

  
      一步步单步跟进:


  0040E89B            03CA             add ecx,edx
  0040E89D            8B01             mov eax,dword ptr ds:[ecx]
  0040E89F            FFD0             call eax                                 ; kernel32.VirtualAlloc

  
      记住这个,这个对分析PECompact加壳的原理有用!


  0040E8E0            8B4B 0C          mov ecx,dword ptr ds:[ebx+C]
  0040E8E3            894E 14          mov dword ptr ds:[esi+14],ecx
  0040E8E6            FFD7             call edi
  //此处,我们可以跟进分析,也可以不跟进,往下看:
  0040E8E6            FFD7             call edi
  0040E8E8            8985 FA120010    mov dword ptr ss:[ebp+100012FA],eax
  0040E8EE            8BF0             mov esi,eax
  0040E8F0            8B4B 14          mov ecx,dword ptr ds:[ebx+14]
  0040E8F3            5A               pop edx
  0040E8F4            EB 0C            jmp short notepad.0040E902
  0040E8F6            03CA             add ecx,edx
  0040E8F8            68 00800000      push 8000
  0040E8FD            6A 00            push 0
  0040E8FF            57               push edi
  0040E900            FF11             call dword ptr ds:[ecx]
  0040E902            8BC6             mov eax,esi
  0040E904            5A               pop edx
  0040E905            5E               pop esi
  0040E906            5F               pop edi
  0040E907            59               pop ecx
  0040E908            5B               pop ebx
  0040E909            5D               pop ebp
  0040E90A            FFE0             jmp eax  //此处就是跳到OEP了

  
      我们还是跟进一下,看看壳是如何处理的吧!


  0003094B            0053 57          add byte ptr ds:[ebx+57],dl
  0003094E            56               push esi
  0003094F            55               push ebp
  00030950            E8 00000000      call 00030955

  000309CC            6A 40            push 40
  000309CE            68 00100000      push 1000
  000309D3            51               push ecx
  000309D4            6A 00            push 0
  000309D6            FF95 291E0010    call dword ptr ss:[ebp+10001E29]         ; kernel32.VirtualAlloc
  
  00030AD8            68 00800000      push 8000
  00030ADD            6A 00            push 0
  00030ADF            FFB5 191E0010    push dword ptr ss:[ebp+10001E19]
  00030AE5            FF95 2D1E0010    call dword ptr ss:[ebp+10001E2D]         ; kernel32.VirtualFree
      //跟到些处,我们发现了与VirtualAlloc相对应的VirtualFree,也发现了大家常说的特征码:push 8000了,……#……
  
  00030AEB            8B46 0C          mov eax,dword ptr ds:[esi+C]
  //载入基址00400000
  00030AEE            03C7             add eax,edi
  //eax=00400000+10CC,就是OEP了
  
  00030AF0            5D               pop ebp
  00030AF1            5E               pop esi
  00030AF2            5F               pop edi
  00030AF3            5B               pop ebx
  00030AF4            C3               retn  //恢复堆栈后,返回

  
  

0040E904            5A               pop edx
  0040E905            5E               pop esi
  0040E906            5F               pop edi
  0040E907            59               pop ecx
  0040E908            5B               pop ebx
  0040E909            5D               pop ebp
  0040E90A          - FFE0             jmp eax             ; notepad.<模块入口点>

  看看此时的寄存器值:


  EAX 004010CC notepad.<模块入口点>
  ECX 0013FFB0
  EDX 7C9585EC ntdll.KiFastSystemCallRet
  EBX 7FFD7000
  ESP 0013FFC4
  EBP 0013FFF0
  ESI 00000000
  EDI 00000000
  EIP 0040E90A notepad.0040E90A

  
  对比一下程序载入时的值:


  EAX 00000000
  ECX 0013FFB0
  EDX 7C9585EC ntdll.KiFastSystemCallRet
  EBX 7FFD8000
  ESP 0013FFC4
  EBP 0013FFF0
  ESI 00000000
  EDI 00000000
  EIP 004010CC notepad.<模块入口点>

  
  =================呵呵,明白了吧!
  …………
  =================不过,你明白了,我自己却还是糊涂着呢!^#^

      还有一种快捷方式:
        1、OD载入后,直接下断点:bp VirtualFree,然后按Shift+F9,就会断在第一次调用处:
  000309D6            FF95 291E0010    call dword ptr ss:[ebp+10001E29]         ; kernel32.VirtualAlloc
        2、然后搜索特征码:Ctrl+F,搜索push 8000,就会来到第二次调用VirtualFree前:


  00030AD8            68 00800000      push 8000
  00030ADD            6A 00            push 0
  00030ADF            FFB5 191E0010    push dword ptr ss:[ebp+10001E19]
  00030AE5            FF95 2D1E0010    call dword ptr ss:[ebp+10001E2D]         ; kernel32.VirtualFree

  现在我们明白了,就可以一次下断bp VirtualFree,连续按两次Shift+F9运行,然后按Alt+F9返回到程序领空,就可以到了最后一个关键点了,呵呵!
  试试了一下:汇编及VB,只要一次Shift+F9或F9就能OK,跟进了一个进去看,也是两次调用VirtualFree,不知为什么只一次就OK!Delphi、Borland C++、VC++需要两次!

发表评论