1,  首先把od调试异常都钩掉,Od 载入 断在:
006530D4 > /EB 01           jmp        006530D7h
两次F7 到:
  006530D8    E8 00000000     call       006530DDh
记住Esp=0012FFA4, 把这个值纪录下来,为了以后对esp下DWORD硬件访问断点到达oep。
由于是双进程壳,就有两种执行流程,父进程执行流程和子进程执行流程,父进程创建并调试子进程,接受子进程调试事件,控制子进程的运行,两种执行流程,必然有个分界点,这里是CreateMutexA,壳对CreateMutexA入口有断点检测,所以在CreateMutexA+0x51下断,这里下硬件断:
7C80EA2D    C2 0C00         retn       000Ch  //下硬件断点
返回到达:
00656DD6    8985 C66C4000   mov        dword ptr [ebp+00406CC6h] , eax
00656DDC    8D85 3A271F03   lea        eax , dword ptr [ebp+031F273Ah]
00656DE2    2D FCCEDE02     sub        eax , 02DECEFCh
00656DE7    FF10            call       dword ptr [eax]
00656DE9    BB CA7DB9FE     mov        ebx , FEB97DCAh //这里改eax=B7,
使程序按照子进程的流程运行
继续单步到:
00656E3D    F1              int1  //产生异常,正常运行的话父进程接受这个异常,并通过GetContextThread 和SetContextThread 改变eip,进而改变子进程的流程,这里改eip= 0x00656E5C
然后运行断在:
0065364A    F3:AE           scasb   //异常,这里不处理
8次Shift+F9忽略8个异常,运行到:
00657766    87DF            xchg       edi , ebx  //这里处理异常,和int1 异常一样,改eip,这里 eip= 00657791
00657791    C3              ret


2,下面开始看他怎么处理IAT 表
00653F44    8B3B            mov        edi , dword ptr [ebx]  开始
00653F46    03BD 1E424000   add        edi , dword ptr [ebp+0040421Eh]
00653F4C    803F 44         cmp        byte ptr [edi] , 44h
。。。
。。。
。。。
00653F7A    3D 88BF46CF     cmp        eax , CF46BF88h  //比较hash值
00653F7F    75 20           jne        00653FA1h
00653F81    8B85 1A424000   mov        eax , dword ptr [ebp+0040421Ah]  //等于处理
00653F87    D1E1            shl        ecx , 1
00653F89    03C1            add        eax , ecx
00653F8B    0FB700          movzx      eax , word ptr [eax]
00653F8E    C1E0 02         shl        eax , 02h
00653F91    0385 26424000   add        eax , dword ptr [ebp+00404226h]
00653F97    8B00            mov        eax , dword ptr [eax]
00653F99    0385 1E424000   add        eax , dword ptr [ebp+0040421Eh]   //得到API地址,EAX 7C831EDD kernel32.DeleteFileA

00653F4到00653F7A是取出API 字符串名字,并运算得到一个函数值,然后比较是不是IAT表里的API,是的话到:
00653D67    8B18            mov        ebx , dword ptr [eax]
这里可以看到开始取DeleteFileA 入口内容,并开始做变形处理存放到
00DF0000   /EB 01           jmp        00DF0003h

00653E23    F3:A4           movsb
这里下断,断几次,会看到00DF0000 里发生变化:
00DF0000   /EB 01           jmp        00DF0003h

00DF0003    8BFF            mov        edi , edi
00DF0005    55              push       ebp
00DF0006    8BEC            mov        ebp , esp
00DF0008    FF75 08         push       dword ptr [ebp+08h]
00DF000B    EB 07           jmp        00DF0014h

00DF0014  ^\EB F8           jmp        00DF000Eh

00DF000E  - E9 D21EA47B     jmp        7C831EE5h     //跳到DeleteFileA+8

在来到这里:

0065418A    8907            mov        dword ptr [edi] , eax   写壳的IAT
0065418C    EB 02           jmp        00654190h

这里edi=00657E1F,eax=DF00000
[esp-3C]-[esp-38]= DeleteFileA

这里可以打补丁修复IAT,我申请的内存地址:E20000
二进制代码:
8B 44 24 C4 2B 44 24 C8 89 07 E9 81 41 83 FF
00E20000    8B4424 C4       mov        eax , dword ptr [esp-3Ch]
00E20004    2B4424 C8       sub        eax , dword ptr [esp-38h]
00E20008    8907            mov        dword ptr [edi] , eax
00E2000A  - E9 814183FF     jmp        00654190h
00E2000F    90              nop

0065418A修改为:
0065418A  - E9 71BE7C00     jmp        00E20000h
0065418F    90              nop

这时把开始记录的 esp=0012FFA4,对0012FFA4下DWORD硬件访问断点,然后运行,直奔stolen OEP:
00654CB5    F7D2    not edx                        ; ntdll.KiFastSystemCallRet
00654CB7    39C2            cmp        edx , eax
00654CB9    F7C0 74E7F921   test       eax , 21F9E774h
00654CBF    0FACC2 48       shrd       edx , eax , 00000048h
00654CC3    0FBDC8          bsr        ecx , eax
00654CC6    C7C2 2431C7CD   mov        edx , CDC73124h
00654CCC    85C0            test       eax , eax
00654CCE    0FBAEA 31       bts        edx , 31h
00654CD2    F7D2            not        edx
00654CD4    F7C1 25C4A65C   test       ecx , 5CA6C425h
00654CDA    3BD0            cmp        edx , eax

3,修复Stolen Code:
首先修复Stolen OEP,观察栈
00654CDF    55              push       ebp            //1
00654CE0    EB 01           jmp        00654CE3h
。。。
00654CE3    8BEC            mov        ebp , esp       //2
00654CE5    EB 01           jmp        00654CE8h
。。。
00654CE8    6A FF           push       FFh         //3
。。。
00654CED    68 683FA8D9     push       D9A83F68h
00654CF2   810424 009CB326 add  dword ptr [esp] , 26B39C00h    //4 push    005BDB68
00654CF9    68 97AB43E7     push       E743AB97h
00654CFE    810424 8181FE18 add  dword ptr [esp] , 18FE8181h  //5  push    00422D18
00654D05    64:A1 00000000  mov        eax , dword ptr fs:[00000000h]  //6
00654D0E    50              push       eax           //7
00654D12    64:8925 0000000>mov        dword ptr fs:[00000000h] , esp    //8
00654D19    EB 01           jmp        00654D1Ch
。。。
00654D1C    83C4 A4         add        esp , A4h          //9
。。。
00654D22    53              push       ebx            //10
00654D23    EB 01           jmp        00654D26h
。。。
00654D26    56              push       esi
00654D27    EB 01           jmp        00654D2Ah        //11
。。。
00654D2A    57              push       edi            //12
00654D2B    EB 01           jmp        00654D2Eh
。。。
00654D2E    8965 E8         mov        dword ptr [ebp-18h] , esp  //13
00654D31    EB 01           jmp        00654D34h
。。。
00654D34 FF15 21816500   call  dword  ptr [00658121h]                 ;kernel32.GetVersion          //14
。。。
00654D3D    A3 A4A75E00     mov        dword ptr [005EA7A4h] , eax  //15
00654D42    EB 01           jmp        00654D45h
。。。
00654D45    A1 A4A75E00     mov        eax , dword ptr [005EA7A4h]  //16
00654D4A    EB 01           jmp        00654D4Dh
。。。
00654D4D    C1E8 08         shr        eax , 08h        //17
00654D50    EB 01           jmp        00654D53h
。。。
00654D53    25 FF000000     and        eax , 000000FFh    //18
00654D58    EB 01           jmp        00654D5Bh
。。。
00654D5B    A3 B0A75E00     mov        dword ptr [005EA7B0h] , eax    //18
00654D60    EB 01           jmp        00654D63h        
。。。
00654D63    8B0D A4A75E00   mov        ecx , dword ptr [005EA7A4h]    //19
00654D69    EB 01           jmp        00654D6Ch
。。。
00654D6C    81E1 FF000000   and        ecx , 000000FFh        //20
00654D72    EB 01           jmp        00654D75h
00654D75  - E9 D58FDCFF     jmp        0041DD4Fh      //跳到程序代码段

在0041DD00到0041DD4F 不上上面代码:
二进制代码:
55 8B EC 6A FF 68 68 DB 5B 00 68 18 2D 42 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 C4 A4
53 56 57 89 65 E8 FF 15 21 81 65 00 A3 A4 A7 5E 00 A1 A4 A7 5E 00 C1 E8 08 25 FF 00 00 00 A3 B0
A7 5E 00 8B 0D A4 A7 5E 00 81 E1 FF 00 00 00

修复后的oep:
0041DD00    55              push       ebp
0041DD01    8BEC            mov        ebp , esp
0041DD03    6A FF           push       FFh
0041DD05    68 68DB5B00     push       005BDB68h
0041DD0A    68 182D4200     push       00422D18h
0041DD0F    64:A1 00000000  mov        eax , dword ptr fs:[00000000h]
0041DD15    50              push       eax
0041DD16    64:8925 0000000>mov        dword ptr fs:[00000000h] , esp
0041DD1D    83C4 A4         add        esp , A4h
0041DD20    53              push       ebx
0041DD21    56              push       esi
0041DD22    57              push       edi
0041DD23    8965 E8         mov        dword ptr [ebp-18h] , esp
0041DD26    FF15 21816500   call       dword ptr [00658121h]                        ; kernel32.GetVersion
0041DD2C    A3 A4A75E00     mov        dword ptr [005EA7A4h] , eax
0041DD31    A1 A4A75E00     mov        eax , dword ptr [005EA7A4h]
0041DD36    C1E8 08         shr        eax , 08h
0041DD39    25 FF000000     and        eax , 000000FFh
0041DD3E    A3 B0A75E00     mov        dword ptr [005EA7B0h] , eax
0041DD43    8B0D A4A75E00   mov        ecx , dword ptr [005EA7A4h]
0041DD49    81E1 FF000000   and        ecx , 000000FFh
0041DD4F    890D ACA75E00   mov        dword ptr [005EA7ACh] , ecx

4,修复IAT,这里我用Universal Import Fixer (UIF) v1.2
New IAT VA:5EE0000

5,修复代码重定向
肉眼观察有3种:
1种
0041DD7C    6A 01           push       01h
0041DD7E    E8 5D24FEFF     call       004001E0h

004001E0  - E9 CB8A0200     jmp        00428CB0h
把call       004001E0h 改成call       00428CB0h

2种
0041DE73  - E9 BC23FEFF     jmp        00400234h
0041DE78    90              nop
0041DE79    90              nop

00400234    833D 9CA75E00 0>cmp        dword ptr [005EA79Ch] , 01h
0040023B  - E9 3ADC0100     jmp        0041DE7Ah

把call       0041DE73  改成cmp        dword ptr [005EA79Ch] , 01h


3种
00401B89    FF15 558C6500   call       dword ptr [00658C55h]     
//这里是对00401B93 后面的代码  解码
00401B8F    DF67 D8         fbld        [edi-28h]
00401B92    46              inc        esi
00401B93    B7 1E           mov        bh , 1Eh
00401B95    4C              dec        esp
00401B96    56              push       esi
00401B97    0102            add        dword ptr [edx] , eax
。。。。。
00401BF8    FF15 798C6500   call       dword ptr [00658C79h]
//这里运行后在对00401B93后面的代码 加密
00401BFE    3F              aas
00401BFF    25 2C218D85     and        eax , 858D212Ch
00401C04    FC              cld
00401C05    FEFF            ???                                                     ; Unknown command
00401C06    FFFF5F          ???                                                     ; Unknown command
00401C07    FF5F 5E         call far   fword ptr [edi+5Eh]
00401C0A    5B              pop        ebx
00401C0B    81C4 58030000   add        esp , 00000358h
00401C11    3BEC            cmp        ebp , esp
00401C13    E8 B8B90100     call       0041D5D0h
00401C18    8BE5            mov        esp , ebp
00401C1A    5D              pop        ebp
00401C1B    C3              ret

前面 1,2种有规律可循,可以直接脚本修复,这里用PeSpin_Code_Redirection_Fix.txt 就可以修复,不过脚本不完善,还得手工修复几处

第3种,手动,运行解密代码后,nop 掉解密代码,和 加密代码,还有之间的 没用的垃圾,
这里我添上我修复的二进制代码,有三处:
00401B83:
89 85 EC FC FF FF 90 90 90 90 90 90 90 90 90 90 C7 85 E8 FC FF FF 00 00 00 00 8B 8D E8 FC FF FF
3B 8D EC FC FF FF 7D 4D 8B 95 E8 FC FF FF 0F BE 84 15 FC FE FF FF 83 E0 06 8B 8D E8 FC FF FF 88
84 0D FC FE FF FF 8B 95 E8 FC FF FF 0F BE 84 15 FC FE FF FF 83 F0 1E 8B 8D E8 FC FF FF 88 84 0D
FC FE FF FF 8B 95 E8 FC FF FF 83 C2 01 89 95 E8 FC FF FF EB A5 90 90 90 90 90 90 90 90 90 90 8D
85 FC FE FF FF 5F 5E 5B 81 C4 58 03 00 00 3B EC E8 B8 B9 01 00 8B E5 5D C3

00401CA6:
90 90 90 90 90 90 90 90 90 90 C7 45 FC 00 00 00 00 EB 09 8B 45 FC 83 C0 01 89 45 FC 8B 4D 08 03
4D FC 0F BE 11 85 D2 74 20 8B 45 08 03 45 FC 0F BE 08 89 4D F8 8B 55 F8 83 C2 36 89 55 F8 8B 45
F8 03 45 F4 89 45 F4 EB CA 90 90 90 90 90 90 90 90 90 90 8B 45 F4 5F 5E 5B 83 C4 4C 3B EC E8 C7
B8 01 00 8B E5 5D C3

401973:
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 8B 85 D8 FE FF FF 3B 85 DC FE FF FF 75 16 6A 00 68 E8 42 5B 00 68 B0 42 5B 00
8B 4D F0 E8 97 F6 07 00 EB 14 6A 00 68 E8 42 5B 00 68 8C 42 5B 00 8B 4D F0 E8 81 F6 07 00

6,Dump文件,并修复IAT
工具LordPE + ImportREC

7,手动修复壳的双进程保护
正常载入od,在WaitForDebugEvent下硬件执行断点,返回到:
00657043    0BC0            or         eax , eax
00657045    0F84 1D060000   je         00657668h
0065704B    8B85 346D4000   mov        eax , dword ptr [ebp+00406D34h]
00657051    35 C19B54D3     xor        eax , D3549BC1h
00657056    3D C29B54D3     cmp        eax , D3549BC2h
0065705B    0F84 DB050000   je         0065763Ch
00657061    3D C09B54D3     cmp        eax , D3549BC0h
00657066    74 50           je         006570B8h
00657068    3D C49B54D3     cmp        eax , D3549BC4h
0065706D    0F84 F5050000   je         00657668h
00657073    3D C39B54D3     cmp        eax , D3549BC3h
00657078    0F84 3A050000   je         006575B8h
0065707E    3D C59B54D3     cmp        eax , D3549BC5h
00657083    0F84 70050000   je         006575F9h

观察ebx= 006569E2 的值:
006569E2  03 00 00 00 C0 09 00 00 10 0F 00 00 58 00 00 00   ...?..  ..X...
006569F2  3C 00 00 00 40 00 00 00 00 00 40 00 00 00 00 00  <...@.....@.....
00656A02  00 00 00 00 00 F0 FD 7F D4 30 65 00 00 00 00 00  .....瘕?e.....
00656A12  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ...............

[Ebx+C]   ExceptionCode 异常代码 这里我们要看ExceptionCode = 0xC000001D
[Ebx+28]  ExceptionAddress就是子进程异常发生的地址

一路跟过来到:
00657B8A    68 486A6500     push       00656A48h
00657B8F    FFB5 9A6C4000   push       dword ptr [ebp+00406C9Ah]
00657B95    8D85 34480E39   lea        eax , dword ptr [ebp+390E4834h]
00657B9B    2D F1EFCD38     sub        eax , 38CDEFF1h
00657BA0    FF10            call       dword ptr [eax]     //GetThreadContext
得到调试线程上下环境
。。。
在来到这里

0065735C    C647 08 00      mov        byte ptr [edi+08h] , 00h                     ; //edi=ExceptionAddress的数字字符串
00657360    8D85 5E241F13   lea        eax , dword ptr [ebp+131F245Eh]
00657366    2D 0ECADE12     sub        eax , 12DECA0Eh
0065736B    FFD0            call       eax

接着对edi=ExceptionAddress的数字字符串进行hash运算,来到这里:

00655746    33FF            xor        edi , edi
00655748    EB 07           jmp        00655751h

edx = hash 值

然后查表:

006573EA    BF 898C6500     mov        edi , 00658C89h    //表的首地址
006573EF    B9 B48A0000     mov        ecx , 00008AB4h
006573F4    E8 03000000     call       006573FCh
。。。。。

00657405    3B07            cmp        eax , dword ptr [edi]     
00657407    74 26           je         0065742Fh      //循环比较hash值,等于就跳
00657409    83C7 0B         add        edi , 0Bh      //这里得到结构大小是B
0065740C    EB 07           jmp        00657415h
0065740E    FA              cli
0065740F    EB 01           jmp        00657412h
00657411    FFEB            jmp far    ebx                                          ; Illegal use of register
00657413    04 E3           add        al , E3h
00657415  ^ EB F8           jmp        0065740Fh
00657417    6983 E90B0BC9 7>imul       eax , dword ptr [ebx-36F4F417h] , 858DD577h
00657421    4B              dec        ebx
00657422    D01E            rcr        byte ptr [esi] , 1
00657424    132D 705CDE12   adc        ebp , dword ptr [12DE5C70h]
0065742A    FFE0            jmp        eax
0065742C    0FFFDE          ???                                                     ; Unknown command
0065742D    FFDE            call far   esi                                          ; Illegal use of register
0065742F    BE 5BE71EFF     mov        esi , FF1EE75Bh
00657434    81EE 137DB9FE   sub        esi , FEB97D13h
0065743A    8D85 221380E1   lea        eax , dword ptr [ebp-1E7FECDEh]
00657440    2D 1B983FE1     sub        eax , E13F981Bh
00657445    FFD0            call       eax            //edi=查找到的地址,开始解释执行
。。。。。

006577C7    0FB647 08       movzx      eax , byte ptr [edi+08h]  //操作码1,转到相应的函数
006577CB    8D9D D5CA1F02   lea        ebx , dword ptr [ebp+021FCAD5h]
006577D1    81EB EE4FDF01   sub        ebx , 01DF4FEEh
006577D7    8B0483          mov        eax , dword ptr [ebx+eax*4]
006577DA    2D 6FD45CE3     sub        eax , E35CD46Fh
006577DF    03C5            add        eax , ebp
006577E1    E8 03000000     call       006577E9h
。。。

006577F2   /FFE0          jmp        eax        //跳到相应的函数
006577F4   |8B4424 26       mov        eax , dword ptr [esp+26h]
006577F8   |85C0            test       eax , eax
006577FA   |5B              pop        ebx
006577FB   |5A              pop        edx
006577FC   |C9              leave
。。。。

006579A9    BB 819C54D3     mov        ebx , D3549C81h
006579AE    81EB C19B54D3   sub        ebx , D3549BC1h
006579B4    8B1433          mov        edx , dword ptr [ebx+esi]   //得到子进程的efl
006579B7    8B47 04         mov        eax , dword ptr [edi+04h]    //操作数
006579BA    0FB65F 09       movzx      ebx , byte ptr [edi+09h]     //操作码2
006579BE    83FB 05         cmp        ebx , 05h
006579C1    74 02           je         006579C5h
006579C3    F7D2            not        edx
006579C5    83E2 01         and        edx , 01h
006579C8    4A              dec        edx
006579C9    0F85 4E010000   jne        00657B1Dh
006579CF    807F 0A 02      cmp        byte ptr [edi+0Ah] , 02h   //指令长度
006579D3    74 0A           je         006579DFh
006579D5    0FBAE0 1F       bt         eax , 1Fh
006579D9    73 2A           jnc        00657A05h
006579DB    F7D8            neg        eax
006579DD    EB 0D           jmp        006579ECh
006579DF    0FBAE0 07       bt         eax , 07h
006579E3    73 20           jnc        00657A05h
006579E5    F7D8            neg        eax                     
006579E7    25 FF000000     and        eax , 000000FFh
006579EC    BB F79E0000     mov        ebx , 00009EF7h
006579F1    81EB 3F9E0000   sub        ebx , 00009E3Fh
006579F7    0FB657 0A       movzx      edx , byte ptr [edi+0Ah]    //计算跳转的地址
006579FB    2BC2            sub        eax , edx
006579FD    290433          sub        dword ptr [ebx+esi] , eax    //修改子进程eip
00657A00    E9 2E010000     jmp        00657B33h
00657A05    BB B6D30000     mov        ebx , 0000D3B6h
00657A0A    81EB FED20000   sub        ebx , 0000D2FEh
00657A10    0FB657 0A       movzx      edx , byte ptr [edi+0Ah]    //计算跳转的地址
00657A14    03C2            add        eax , edx
00657A16    010433          add        dword ptr [ebx+esi] , eax    //修改子进程eip
00657A19    E9 15010000     jmp        00657B33h
。。。
最后通过SetContextThread 改变子进程线程上下环境,来运行子进程

以上分析,可以得到表的结构:
struct Pepsin
{
  异常发生地址的hash值    // 4个字节
  操作数                   //4个字节
   操作码1         //1个字节
   操作码2         //1个字节
   指令长度                //1个字节
};
只要知道操作码1、操作码2和操作数,所代表汇编代码,遍历表00658C89,就能修复 8dc0 异常了!

8,最后运行程序,看看是否还有需要修复的代码,对照着修改!

Ok,总算搞捏!


附上两个脚本:
一个双进程处理脚本.txt脚本 直接跑到:
0065418A    8907            mov        dword ptr [edi] , eax
一个PeSpin_Code_Redirection_Fix.txt 脚本,修复代码重定向

上传的附件 Unpackme.rar