这几天研究脱壳,上论坛看到一老兄求助地址(http://bbs.pediy.com/showthread.php?t=92330),由于自己也是新手,所以下载下来研究半天也无进展,幸好得到看雪老大的帮助,让我柳暗花明又一村,呵呵,经过老大的详细指点,终于将这个壳去掉了,下面将我的心得写出来,也算是留个记号吧,好久没来看雪发文章了!

    OD载入后,不分析,如图,一开始就是一个异常安装,并故意产生一个向[00000000]写入的异常如图:
   

    SHIFT+F7进入异常处理,在ZWContinue前看堆栈中有一个地址是00401016,如图:

  

    到00401016处,是一个无条件跳转指令:

  

    那么我们就到00720FAF处直接下断,然后F9到此处,如图:

   

    取消此处的断点,然后继续向下跑,来到此处:

     

    此时,应该进入到此CALL内部,因为直接F8的话会产生不能继续的异常(进程终止),估计此CALL中有作怪的地方,F7进入:
  
   

   继续向下,来到这里,果然发现了捣乱的地方:

   

    此处的两个je任意一个让其实现即可避过壳的检测。如果用SoftICE,会有通过CreateFile检测调试器的代码,本文忽略。过了拦路虎,就能顺利通过此CALL了,如图:

    

    继续F8向下,发现一个大的跨段跳跃,通过它走向OEP处的(如图):

   

    F8来到了程序的OEP,此时DUMP,然后用ImportREC修复,发现有很多无效的的函数指针,如图:

   

    这时可以用它强行一个一个地对函数的IAT进行修复,但是数量十分大,上百个函数,得找到一个更明智的办法才行啊!为什么加壳的程序能正常运行,而我们脱出来的就不行了,还有这么多无效的指针?应该是壳对部分的IAT进行了加密处理,只要找到了加密部分,绕过去不就能正常脱壳了么?

    然后就来实现吧,CTRL+F2重新载入程序,找到IAT的起始地址 1D4090加上基址就是5D4090,CTRL+F2重新载入程序,d 5d4090, 在此处下硬件写入断点

   

    重复前面的一些步骤,F9几次以后来到这里,发现向IAT的首地址写入了数据:
 
   

    而后面是一个回跳,继续向IAT的后续地址写入函数指针,所以可以判断,这就是IAT的加密代码部分(这个壳加密的是kernel32.dll中的部分函数IAT):

003914A7    C783 CC1A0010 0>mov     dword ptr [ebx+10001ACC], 0
003914B1    8B02            mov     eax, dword ptr [edx]
003914B3    85C0            test    eax, eax
003914B5    74 67           je      short 0039151E
003914B7    52              push    edx
003914B8    8983 CC1A0010   mov     dword ptr [ebx+10001ACC], eax
003914BE    A9 00000080     test    eax, 80000000
003914C3    74 09           je      short 003914CE
003914C5    25 FFFFFF7F     and     eax, 7FFFFFFF
003914CA    6A 00           push    0
003914CC    EB 0E           jmp     short 003914DC
003914CE    8B4D 08         mov     ecx, dword ptr [ebp+8]
003914D1    0341 08         add     eax, dword ptr [ecx+8]
003914D4    33C9            xor     ecx, ecx
003914D6    66:8B08         mov     cx, word ptr [eax]
003914D9    51              push    ecx
003914DA    40              inc     eax
003914DB    40              inc     eax
003914DC    50              push    eax
003914DD    FF75 FC         push    dword ptr [ebp-4]
003914E0    FF93 0A210010   call    dword ptr [ebx+1000210A]
003914E6    5A              pop     edx
003914E7    50              push    eax
003914E8    8B02            mov     eax, dword ptr [edx]
003914EA    A9 00000080     test    eax, 80000000
003914EF    75 18           jnz     short 00391509
003914F1    8B4D 08         mov     ecx, dword ptr [ebp+8]
003914F4    0341 08         add     eax, dword ptr [ecx+8]
003914F7    C600 00         mov     byte ptr [eax], 0
003914FA    40              inc     eax
003914FB    C600 00         mov     byte ptr [eax], 0
003914FE    40              inc     eax
003914FF    8A08            mov     cl, byte ptr [eax]
00391501    C600 00         mov     byte ptr [eax], 0
00391504    40              inc     eax
00391505    84C9            test    cl, cl
00391507  ^ 75 F6           jnz     short 003914FF
00391509    58              pop     eax
0039150A    85C0            test    eax, eax
0039150C  ^ 0F84 3FFFFFFF   je      00391451
00391512    8906            mov     dword ptr [esi], eax
00391514    8902            mov     dword ptr [edx], eax
00391516    83C2 04         add     edx, 4
00391519    83C6 04         add     esi, 4
0039151C  ^ EB 89           jmp     short 003914A7
    
    我们要让IAT部分得到正确的地址,就必须让EAX的值是对应的函数地址值!由于我们到达加密IAT代码部分时IAT的首部已经被写入了加密的IAT值,也就是说加密函数至少已经运行了一次!所以此时必须CTRL+F2再次重新载入程序,来到加密代码首部,然后继续向下,修改代码如下,保持EDX的值是压栈时的值,得到正确的函数地址指针:

   

    这样,这个加密IAT的部分就相当于被我们绕过去了。直接F4到加密结束部分,发现IAT部分已经被写入了正确的函数地址信息:

   

    最后,再次将我们修改的部分还原,就可以直接到达原来的OEP处了!(CTRL+G,输入原来我们找到的OEP地址,F2下断,F9到达后dump即可!)再用ImportREC修复时,发现所有的IAT都有效了,如图:

   

    修复后程序能正常运行,PEID查壳,VC++编写: