【脱壳文件】自己写的一个加载DLL的DD(Delphi写的)
【下载地址】见附件
【加壳方式】ASProtect 2.3 SKE Build 03.19 Beta 除了Protect Original EntryPoint全部选项
【作    者】h_f22
【作者声明】水平很菜 请高手们多指教
【调试环境】WinXPSP2、OllyDBD110、LordPE、ImportREC
【脱壳过程】见下

一、前言
    
    关于Aspr的文章论坛里面已经不少,各位大虾也都基本上把它研究透了。写此文的目的只在于自己学习
和给跟我有相同问题的人一点提示。
    
    Aspr变得越来越强,从没有stolen code到在OEP处偷一点,再到OEP处偷一堆,现在他终于在别处也开始偷了.等一下我们将看到在这个版本的Aspr中出现了一个的stolen code(不是stolen OEP),虽然他只偷了一个函数,也很容易找回来,但是这只是Beta版,正式版的时候又会是什么样呢?也许Aspr要变成超级猛壳了。
    
    加壳用的Aspr2.3时在工具区下载的。程序是自己用Delphi写的一个加载DLL的小工具。
    
二、加壳方式
    
    除了Protect Original EntryPoint(就是stolen OEP)以外的全部选项,虽然没选这个选项,Aspr却在别的地方偷了一点儿。

三、过程
    
    1、找到OEP和IAT
    这个过程很简单。首先用OD加载目标程序,忽略除了INT3以外的全部异常,F9运行,停在第二个异常处,在内存映像中找到程序的代码段,下内存访问断点F2,运行,即停在OEP。

代码:
0045AF16      00            db      00 0045AF17      00            db      00 0045AF18      14AD4500      dd      Project1.0045AD14 0045AF1C   .  55            push    ebp             //OEP                ;  Project1.00400000 0045AF1D   .  8BEC          mov     ebp, esp 0045AF1F   .  83C4 F0       add     esp, -10 0045AF22   .  B8 3CAD4500   mov     eax, 0045AD3C 0045AF27   .  E8 E0B1FAFF   call    0040610C 0045AF2C   .  A1 F4C04500   mov     eax, [45C0F4] 0045AF31   .  8B00          mov     eax, [eax] 0045AF33   .  E8 08E3FFFF   call    00459240 0045AF38   .  8B0D D8C14500 mov     ecx, [45C1D8]                   ;  Project1.0045DC04 0045AF3E   .  A1 F4C04500   mov     eax, [45C0F4] 0045AF43   .  8B00          mov     eax, [eax] 0045AF45   .  8B15 B4A84500 mov     edx, [45A8B4]                   ;  Project1.0045A900    



    找到OEP=45AF1C,之后找IAT。由于这个程序是Delphi的,到代码段的前部就可以找到:

代码:
004011FD   .  626A 65       bound   ebp, [edx+65] 00401200   .  63748B C0     arpl    [ebx+ecx*4-40], si 00401204   $  E8 F7ED1501   call    01560000     //Advance Import protection的处理函数 00401209      14            db      14 0040120A      8BC0          mov     eax, eax 0040120C   .- FF25 ACE14500 jmp     [45E1AC]     //45E1AC就是IAT的某个地址了 00401212   .  8BC0          mov     eax, eax 00401214   .- FF25 A8E14500 jmp     [45E1A8]                        ;  ntdll.RtlUnwind 0040121A   .  8BC0          mov     eax, eax 0040121C   $- FF25 A4E14500 jmp     [45E1A4]                        ;  kernel32.UnhandledExceptionFilter 00401222   .  8BC0          mov     eax, eax 00401224   .  E8 D7ED1501   call    01560000 00401229   .  E4 8B         in      al, 8B 0040122B   .  C0FF 25       sar     bh, 25 0040122E   ?  C4E1          les     esp, ecx                        ;  非法使用寄存器 00401230   ?  45            inc     ebp 00401231   ?  008B C0FF259C add     [ebx+9C25FFC0], cl 00401237   ?  E1 45         loopde  short 0040127E 00401239   ?  008B C0E8BFED add     [ebx+EDBFE8C0], cl 0040123F   ?  15 012E8BC0   adc     eax, C08B2E01


    
    沿着45E1AC处上下找一找就可以很容易的找到IAT了,从0045E12C到0045E744,长度620.很显然加密了:

代码:
0045E0EC  C0 E6 05 00 00 00 00 00 00 00 00 00 00 00 00 00  梨............. 0045E0FC  3A FF 05 00 E4 E6 05 00 00 00 00 00 00 00 00 00  :.滏......... 0045E10C  00 00 00 00 48 01 06 00 44 E7 05 00 00 00 00 00  ....H.D?..... 0045E11C  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 0045E12C  8A 18 93 7C ED 10 92 7C 05 10 92 7C A1 9F 80 7C  ?搢?抾抾| 0045E13C  14 9B 80 7C 81 9A 80 7C 5D 99 80 7C BD 99 80 7C  泙|仛|]檧|綑| 0045E14C  AB 14 81 7C EA 28 C0 8B 94 97 80 7C 7B 97 80 7C  ?亅?缷敆|{梹| 0045E15C  59 B8 80 7C C7 A0 80 7C AD 9C 80 7C F6 3D B4 E4  Y竴|莀|瓬|?翠 0045E16C  11 03 81 7C 73 F4 93 DC B0 C0 EB 01 4D 11 47 F7  亅s魮馨离MG



    我们还得到了Advance Import Protection函数的地址(AIP call)01560000,记下待用。    

    2、避开IAT加密
    这个过程比较简单,跟之前的Aspr没多大区别。首先用OD加载目标程序,忽略除了INT3以外的全部异常
F9运行停在第一个异常处,右键选择查找-〉所有参考文本字串,找到连着的两个85,双击找到这里:

代码:
     00E3872E    F3:A5           rep     movs dword ptr es:[edi], dword > 00E38730    66:A5           movs    word ptr es:[edi], word ptr [es> 00E38732    5E              pop     esi 00E38733    EB 0A           jmp     short 00E3873F 00E38735    68 C089E300     push    0E389C0                         ; ASCII "85",CR,LF 00E3873A    E8 C5CEFDFF     call    00E15604 00E3873F    A1 78B9E300     mov     eax, [E3B978] 00E38744    8B00            mov     eax, [eax] 00E38746    E8 410FFFFF     call    00E2968C    //F4到这里后F7步进 00E3874B    84C0            test    al, al 00E3874D    75 0A           jnz     short 00E38759 00E3874F    68 C089E300     push    0E389C0                         ; ASCII "85",CR,LF 00E38754    E8 ABCEFDFF     call    00E15604 00E38759    A1 40BAE300     mov     eax, [E3BA40] 00E3875E    8B40 04         mov     eax, [eax+4] 00E38761    50              push    eax 00E38762    56              push    esi 00E38763    E8 3033FEFF     call    00E1BA98



    步入到00E38746处的call后向下找到这里:

代码:
00E2979A   /75 0A           jnz     short 00E297A6 00E2979C   |68 F497E200     push    0E297F4                         ; ASCII "180",CR,LF 00E297A1   |E8 5EBEFEFF     call    00E15604 00E297A6   \834424 08 04    add     dword ptr [esp+8], 4 00E297AB    47              inc     edi 00E297AC    EB 1A           jmp     short 00E297C8 00E297AE    83C7 02         add     edi, 2 00E297B1    8BC7            mov     eax, edi 00E297B3    50              push    eax 00E297B4    55              push    ebp 00E297B5    8D4424 10       lea     eax, [esp+10] 00E297B9    50              push    eax 00E297BA    56              push    esi 00E297BB    E8 6CFCFFFF     call    00E2942C           //F4到这里F7步入 00E297C0    0FB707          movzx   eax, word ptr [edi] 00E297C3    83C0 02         add     eax, 2 00E297C6    03F8            add     edi, eax 00E297C8    8A1F            mov     bl, [edi] 00E297CA    47              inc     edi 00E297CB    3A5E 34         cmp     bl, [esi+34] 00E297CE  ^ 0F85 77FFFFFF   jnz     00E2974B 00E297D4    8BDF            mov     ebx, edi 00E297D6    8B03            mov     eax, [ebx] 00E297D8    85C0            test    eax, eax 00E297DA  ^ 0F85 0AFFFFFF   jnz     00E296EA 00E297E0    8A0424          mov     al, [esp] 00E297E3    83C4 0C         add     esp, 0C 00E297E6    5D              pop     ebp 00E297E7    5F              pop     edi 00E297E8    5E              pop     esi 00E297E9    5B              pop     ebx 00E297EA    C3              retn



    进入00E297BB处的Call后就是处理IAT的地方了,接下来就是找对应情况然后PATCH了:

代码:
00E29447    83E8 02         sub     eax, 2 00E2944A    0FB630          movzx   esi, byte ptr [eax] 00E2944D    8B45 10         mov     eax, [ebp+10] 00E29450    83E8 02         sub     eax, 2 00E29453    0FB600          movzx   eax, byte ptr [eax] 00E29456    3B43 2C         cmp     eax, [ebx+2C] 00E29459    76 06           jbe     short 00E29461 00E2945B    8943 2C         mov     [ebx+2C], eax 00E2945E    EB 01           jmp     short 00E29461 00E29460    6933 C08A433B   imul    esi, [ebx], 3B438AC0 00E29466    3BF0            cmp     esi, eax                 //在这里下硬件断点 00E29468    75 5E           jnz     short 00E294C8           //这里改成jmp 01550000 跳到Patch代码中去 00E2946A    EB 01           jmp     short 00E2946D 00E2946C    C7              ???                                     ; 未知命令 00E2946D    66:8B02         mov     ax, [edx] 00E29470    66:8945 FA      mov     [ebp-6], ax 00E29474    83C2 02         add     edx, 2 00E29477    8955 FC         mov     [ebp-4], edx



    在00E29466处下硬件断点,用F9不断运行,同时观察数据窗口里面IAT的变化,如果在ESI的某个值时IAT
中的值被解码就是第一种或第二种情况,没有变化就是第三种情况。这里和前面的Aspr有点不同的是一共只有
3种情况,也就是说没有处理GetProcAddress的情况,事实上如果你查看加密的IAT会发现GetProcAddress在里
面。不知道是不是Beta版的关系还是Aspr觉得没什么必要?

    我这里的三种情况分别是:第一种B7 第二种CF 第三种82。接下来就是Patch了,用插件HidenOD分出一块空
间,贴上我自己写的一段代码,里面除了把第三种情况变成第二种情况以外还多出了另外其他情况的处理。如果有非
以上三种情况的ESI值出现Patch代码会自动停下来,不过运行前要不忽略INT3中断。如下:

代码:
01550000  - 0F84 67948DFF   je      00E2946D //第一种 01550006    81FE 82000000   cmp     esi, 82 0155000C    0F84 0C000000   je      0155001E//第三种 01550012    81FE CF000000   cmp     esi, 0CF 01550018    0F85 0A000000   jnz     01550028//不是前三种 0155001E    BE CF000000     mov     esi, 0CF 01550023  - E9 A0948DFF     jmp     00E294C8 01550028    CC              int3    //如果出现不是前三种情况会停在这里 01550029  ^ EB F3           jmp     short 0155001E 0155002B    90              nop



二进制:

0F 84 67 94 8D FF 81 FE 82 00 00 00 0F 84 0C 00 00 00 81 FE CF 00 00 00 0F 85 0A 00 00 00 BE CF
00 00 00 E9 A0 94 8D FF CC EB F3 90 00 00 00 00
    
    以上的代码原来用来处理Aspr2.1的现在用来Aspr2.3也一样,不过就目前看他永远不会自己停下来,因为不存在
第四种情况。上面的代码稍微改一下就可以用在你自己的Aspr2.X上,不过要注意的是为了方便所有的转跳都是long的。

    把00E29468改成jmp 01550000,运行一下就可以得到了完整的IAT了(很有可能跑飞,注意保存数据):

代码:
8A 18 93 7C ED 10 92 7C 05 10 92 7C A1 9F 80 7C 14 9B 80 7C 81 9A 80 7C 5D 99 80 7C BD 99 80 7C AB 14 81 7C 37 97 80 7C 94 97 80 7C 7B 97 80 7C 59 B8 80 7C C7 A0 80 7C AD 9C 80 7C E0 C6 80 7C 11 03 81 7C D3 2F 88 7C 05 A4 80 7C EE 1E 80 7C 28 AC 80 7C 29 B5 80 7C 57 B3 80 7C 7E D4 80 7C 8D 2C 81 7C 66 AA 80 7C 59 35 81 7C D7 EF 80 7C A2 CA 81 7C 9F 0F 81 7C 8A 2B 86 7C 40 7A 95 7C E1 EA 81 7C A9 2C 81 7C 00 00 00 00 B3 11 D3 77 E8 0F D2 77 EA 04 D5 77 90 0F D2 77 00 00 00 00 83 78 DA 77 1B 76 DA 77 F0 6B DA 77 00 00 00 00 50 48 0F 77 9D C9 11 77 59 4B 0F 77 00 00 00 00 。。。。。。。



    IAT建议复制出来,我们等一下要重来。

    3、处理AIP
    接下来就是处理AIP的函数了,首先来到OEP处,然后把刚才得到的IAT贴回去。之后分一段内存贴上我写的一段代码,
这段代码也是用脱Aspr2.1改的,下面说说这段代码怎么用:

    这段代码可以贴在任何地址处而不用修改任何一个字节,但是它需要一些变量,你在运行之前要填上这些变量。如果
你的代码被贴在0040000,那么:

    0040000+100 程序代码段开始地址
    0040000+104 程序代码段结束地址+1
    0040000+108 ESP保存地址
    0040000+10C 保存解码API地址
    0040000+110 IAT开始地址
    0040000+114 IAT结束地址+4
    0040000+118 解码call地址
    0040000+11C 未找到API个数记录

    你需要填的是目标程序的代码段开始地址、程序代码段结束地址+1、IAT开始地址、IAT结束地址+4和解码call地址。
其余的就不用管了,我们这里:
    
    程序代码段开始地址=00401000
    程序代码段结束地址+1=0045B000
    IAT开始地址=0045E12C
    IAT结束地址+4=0045E748
    解码call地址(AIP call)=01560000

    注意x86的数据是big end,就是低位在前高位在后,别填倒了:
    
    填完后整个数据窗口应该是这样:

代码:
00FB0000  E8 00 00 00 00 5B 83 EB 05 8B 93 00 01 00 00 80  ?...[冸嫇... 00FB0010  3A E8 0F 85 94 00 00 00 8B 42 01 03 C2 83 C0 05  :?厰...婤聝? 00FB0020  3B 83 18 01 00 00 0F 85 80 00 00 00 90 90 90 90  ;?..厐...悙悙 00FB0030  90 90 90 90 90 90 90 90 60 89 A3 08 01 00 00 FF  悙悙悙悙`墸.. 00FB0040  E2 E8 00 00 00 00 5B 83 EB 46 89 83 0C 01 00 00  忤....[冸F墐... 00FB0050  8B A3 08 01 00 00 61 8B 8B 10 01 00 00 8B 83 0C  嫞..a媼..媰. 00FB0060  01 00 00 39 01 0F 85 0D 00 00 00 66 C7 02 FF 25  ..9?...f?% 00FB0070  89 4A 02 E9 34 00 00 00 83 C1 04 3B 8B 14 01 00  塉?...兞;?. 00FB0080  00 0F 82 DC FF FF FF FF 83 1C 01 00 00 90 90 90  .傑?..悙 00FB0090  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90  悙悙悙悙悙悙悙悙 00FB00A0  90 90 90 90 90 90 90 90 90 90 90 90 42 3B 93 04  悙悙悙悙悙悙B;? 00FB00B0  01 00 00 0F 82 56 FF FF FF EB FE 00 00 00 00 00  ..俈膻..... 00FB00C0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 00FB00D0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 00FB00E0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 00FB00F0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 00FB0100  00 10 40 00 FC AF 45 00 44 FF 12 00 1E 31 32 76  .@.E.D.12v 00FB0110  2C E1 45 00 44 E7 45 00 00 00 56 01 01 00 00 00  ,酔.D鏓...V...



    00FB0100处开始就是变量表了。

    以下是代码(有点长,主要是为了以后加东西):

代码:
     00FB0000    E8 00000000     call    00FB0005    00FB0005    5B              pop     ebx 00FB0006    83EB 05         sub     ebx, 5                     //用ebx取得代码所在地址 ebx是变量的基址 00FB0009    8B93 00010000   mov     edx, [ebx+100]              00FB000F    803A E8         cmp     byte ptr [edx], 0E8 00FB0012    0F85 94000000   jnz     00FB00AC                   //查找call xxxxxxx 00FB0018    8B42 01         mov     eax, [edx+1] 00FB001B    03C2            add     eax, edx 00FB001D    83C0 05         add     eax, 5                     //计算出call去哪里 00FB0020    3B83 18010000   cmp     eax, [ebx+118]             //比较一下是不是去AIP的call 00FB0026    0F85 80000000   jnz     00FB00AC                   //不是就继续找 00FB002C    90              nop                                //是就处理 00FB002D    90              nop 00FB002E    90              nop 00FB002F    90              nop 00FB0030    90              nop 00FB0031    90              nop 00FB0032    90              nop 00FB0033    90              nop 00FB0034    90              nop 00FB0035    90              nop 00FB0036    90              nop 00FB0037    90              nop 00FB0038    60              pushad                                 00FB0039    89A3 08010000   mov     [ebx+108], esp             //保存现场 00FB003F    FFE2            jmp     edx                        //去AIP的call 00FB0041    E8 00000000     call    00FB0046                   //中断返回 00FB0046    5B              pop     ebx 00FB0047    83EB 46         sub     ebx, 46                    //重新取回变量基址 00FB004A    8983 0C010000   mov     [ebx+10C], eax             //保存解码出的API函数地址 这里如果是Aspr2.1的要把eax改成edx 00FB0050    8BA3 08010000   mov     esp, [ebx+108] 00FB0056    61              popad                              //恢复现场 00FB0057    8B8B 10010000   mov     ecx, [ebx+110]             //在IAT中查到该API函数地址所在 00FB005D    8B83 0C010000   mov     eax, [ebx+10C] 00FB0063    3901            cmp     [ecx], eax 00FB0065    0F85 0D000000   jnz     00FB0078                   //是否找到 00FB006B    66:C702 FF25    mov     word ptr [edx], 25FF       //找到就处理 这里要注意 一般Delphi都是jmp [xxxxx]就是 25FF  00FB0070    894A 02         mov     [edx+2], ecx               //不过也不完全一定,适当的时候要自己改成15FF 00FB0073    E9 34000000     jmp     00FB00AC                   //找到就继续下一个 00FB0078    83C1 04         add     ecx, 4 00FB007B    3B8B 14010000   cmp     ecx, [ebx+114]             //是否IAT结束  00FB0081  ^ 0F82 DCFFFFFF   jb      00FB0063 00FB0087    FF83 1C010000   inc     dword ptr [ebx+11C]        //结束说明没有找到 未找到API个数记录 变量+1 00FB008D    90              nop 00FB008E    90              nop 00FB008F    90              nop 00FB0090    90              nop 00FB0091    90              nop 00FB0092    90              nop 00FB0093    90              nop 00FB0094    90              nop 00FB0095    90              nop 00FB0096    90              nop 00FB0097    90              nop 00FB0098    90              nop 00FB0099    90              nop 00FB009A    90              nop 00FB009B    90              nop 00FB009C    90              nop 00FB009D    90              nop 00FB009E    90              nop 00FB009F    90              nop 00FB00A0    90              nop 00FB00A1    90              nop 00FB00A2    90              nop 00FB00A3    90              nop 00FB00A4    90              nop 00FB00A5    90              nop 00FB00A6    90              nop 00FB00A7    90              nop 00FB00A8    90              nop 00FB00A9    90              nop 00FB00AA    90              nop 00FB00AB    90              nop 00FB00AC    42              inc     edx 00FB00AD    3B93 04010000   cmp     edx, [ebx+104] 00FB00B3  ^ 0F82 56FFFFFF   jb      00FB000F                          //代码段结束? 00FB00B9  - EB FE           jmp     short 00FB00B9                    //原地等待



二进制:

E8 00 00 00 00 5B 83 EB 05 8B 93 00 01 00 00 80 3A E8 0F 85 94 00 00 00 8B 42 01 03 C2 83 C0 05
3B 83 18 01 00 00 0F 85 80 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 60 89 A3 08 01 00 00 FF
E2 E8 00 00 00 00 5B 83 EB 46 89 83 0C 01 00 00 8B A3 08 01 00 00 61 8B 8B 10 01 00 00 8B 83 0C
01 00 00 39 01 0F 85 0D 00 00 00 66 C7 02 FF 25 89 4A 02 E9 34 00 00 00 83 C1 04 3B 8B 14 01 00
00 0F 82 DC FF FF FF FF 83 1C 01 00 00 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 42 3B 93 04 01 00 00 0F 82 56 FF FF FF EB FE

    这段代码贴上后还不算完,我们还要让壳的高级API保护的函数(AIP call)跳回到我们这段代码中,在Aspr2.1
中我们可以找一段syscom提供的特征码然后patch一个jmp就可以了,但是在Aspr2.3中这招行不通。前几天,有人发
了Aspr2.2和2.3的脱文中提供的方法与Aspr2.1基本相同,但是在我这里行不通。我想可能是加壳时的选项不同导致的。

    为了搞定这个问题只好自己跟一下这个call了,由于跟踪的过程比较繁琐,也很枯燥,就不详细写了。不过发现这个
call现在没办法在里面Patch代码,它采用一种层进式的检测修改的方式,每一段代码要先检测下面需要运行的代码是否
被修改,如果被修改就会在解码API的时候发生错误,而且,现在看来他也不走syscom提供特征码的那段代码了。

    所以解决这种问题的最好方法就是脚本了(强烈感谢SHaG编写如此NB的插件,我对你的敬仰简直有如滔滔江水连绵不
绝。。。省略一千字)。

    在内存映像中查找如下内容:03 45 08 8B 00 03 45 08 8B 55 14 29 D0 89 45 FC 5A 8B 45 FC
    就是这里:

代码:
     00E358EF    C1E0 02         shl     eax, 2 00E358F2    0342 1C         add     eax, [edx+1C] 00E358F5    0345 08         add     eax, [ebp+8] 00E358F8    8B00            mov     eax, [eax] 00E358FA    0345 08         add     eax, [ebp+8]    00E358FD    8B55 14         mov     edx, [ebp+14]  //API的地址在这里的EAX中昙花一现 在这里下硬件断点 00E35900    29D0            sub     eax, edx       //这里马上就加密了 00E35902    8945 FC         mov     [ebp-4], eax 00E35905    5A              pop     edx 00E35906    8B45 FC         mov     eax, [ebp-4]



    在00E358FD处下硬件断点,然后回到我们的Patch代码处,在第一句上右键-〉此处新建EIP,之后运行这个脚本:

代码:
loop: run cob mov eip,00FB0041//这里的地址是我们Patch代码的中断返回处 jmp loop



    脚本运行后OD开始工作,等一段时间(比较慢),OD不闪了以后暂停脚本的运行,之后暂停程序的运行。顺序一定
不要错,程序会停在最后一行代码处。

    我们到前面看看,这时AIP call都已经修复了:

代码:
004011FD   .  626A 65       bound   ebp, [edx+65] 00401200   .  63748B C0     arpl    [ebx+ecx*4-40], si 00401204   $- FF25 B0E14500 jmp     [45E1B0]                         ;  kernel32.GetStdHandle 0040120A      8BC0          mov     eax, eax 0040120C   .- FF25 ACE14500 jmp     [45E1AC]                         ;  kernel32.RaiseException 00401212      8BC0          mov     eax, eax 00401214   .- FF25 A8E14500 jmp     [45E1A8]                         ;  ntdll.RtlUnwind 0040121A      8BC0          mov     eax, eax 0040121C   $- FF25 A4E14500 jmp     [45E1A4]                         ;  kernel32.UnhandledExceptionFilter 00401222      8BC0          mov     eax, eax 00401224   $- FF25 A0E14500 jmp     [45E1A0]                         ;  kernel32.WriteFile 0040122A      8BC0          mov     eax, eax 0040122C   $- FF25 C4E14500 jmp     [45E1C4]                         ;  user32.CharNextA 00401232      8BC0          mov     eax, eax 00401234   .- FF25 9CE14500 jmp     [45E19C]                         ;  kernel32.ExitProcess 0040123A      8BC0          mov     eax, eax 0040123C   $- FF25 C0E14500 jmp     [45E1C0]                         ;  user32.MessageBoxA 00401242      8BC0          mov     eax, eax 00401244   $- FF25 98E14500 jmp     [45E198]                         ;  kernel32.FindClose 0040124A      8BC0          mov     eax, eax 。。。。。



    4、Dump、修复和stolen code
    接下来就是Dump+Imp修复了。搞定后本以为大功告成,但却运行不了,难道有自校验?不对,这是我自己写的东西怎么会
有自校验?只好用OD加载跟一下了,加载后按F9运行,OD提示不知如何运行,因为015A0000处不可读。一看就知道时壳内的地
址,看来这是Aspr2.3的新花样了。看看堆栈:

代码:
0012FBE8   004503F0  返回到 dumped_.004503F0 来自 dumped_.00407FDC 0012FBEC   0012FC34 0012FBF0   004503B8  dumped_.004503B8 0012FBF4   00DB3684  ASCII "Form1" 0012FBF8   00000000 0012FBFC   00413CA9  返回到 dumped_.00413CA9 0012FC00   00DB3684  ASCII "Form1" 0012FC04   00000000



    重新加载,到004503F0处:

代码:
004503E0   .  F643 1D 02    test    byte ptr [ebx+1D], 2 004503E4   .  75 0E         jnz     short 004503F4 004503E6   .  8B53 08       mov     edx, [ebx+8] 004503E9   .  8BC5          mov     eax, ebp 004503EB   .  E8 EC7BFBFF   call    00407FDC   //这个call引发的异常 004503F0   .  85C0          test    eax, eax 004503F2   .  74 3A         je      short 0045042E 004503F4   >  47            inc     edi 004503F5   .  4E            dec     esi 004503F6   .^ 75 DA         jnz     short 004503D2



    看来上面的那个Call有问题了,在其上设断点,F7步进,看到了这个:

代码:
00407FDC      68 00005A01   push    15A0000   //这两句跳到壳里去了 00407FE1  \.  C3            retn              //用retn当作转跳,相当于jmp 15A0000 00407FE2      B7            db      B7 00407FE3      68            db      



    现在问题明白了,Aspr2.3在这里把这个函数偷走了。看来要带壳调一下加壳的程序了,用OD重新加载目标程序
(不是脱壳后的),来到OEP处,在00407FDC上下断,F9运行,停下后按两次F8,我们来到了壳里:

代码:
015A0000    56              push    esi 015A0001    57              push    edi 015A0002    53              push    ebx 015A0003    8D744B 9A       lea     esi, [ebx+ecx*2-66] 015A0007    C1C6 1B         rol     esi, 1B 015A000A    C1C6 F7         rol     esi, 0F7 015A000D    8D7420 3C       lea     esi, [eax+3C] 015A0011    8D740E C4       lea     esi, [esi+ecx-3C] 015A0015    2BF1            sub     esi, ecx 015A0017    8D7C51 E7       lea     edi, [ecx+edx*2-19] 015A001B    EB 02           jmp     short 015A001F 015A001D    CD20 8D7C4B16   vxdcall 164B7C8D 015A0023    83EF 16         sub     edi, 16 015A0026    8D7C35 E3       lea     edi, [ebp+esi-1D] 015A002A    2BFE            sub     edi, esi 015A002C    8D7C0A 63       lea     edi, [edx+ecx+63] 015A0030    F3:             prefix rep: 015A0031    EB 02           jmp     short 015A0035 015A0033    CD20 2BF9EB01   vxdjump 1EBF92B 015A0039  - E9 8D7F9D09     jmp     0AF77FCB 015A003E    C07403 8B 40    sal     byte ptr [ebx+eax-75], 40 015A0043    FC              cld 015A0044    09D2            or      edx, edx 015A0046    74 03           je      short 015A004B 015A0048    8B52 FC         mov     edx, [edx-4] 015A004B    B9 4EE14A00     mov     ecx, 4AE14E 015A0050    B9 86C54000     mov     ecx, 40C586 015A0055    50              push    eax 015A0056    2BCD            sub     ecx, ebp 015A0058    59              pop     ecx 015A0059    39D1            cmp     ecx, edx 015A005B    76 02           jbe     short 015A005F 015A005D    89D1            mov     ecx, edx 015A005F    39C9            cmp     ecx, ecx 015A0061    F3:A6           repe    cmps byte ptr es:[edi], byte ptr> 015A0063    74 2A           je      short 015A008F 015A0065    8A5E FF         mov     bl, [esi-1] 015A0068    80FB 61         cmp     bl, 61 015A006B    72 08           jb      short 015A0075 015A006D    80FB 7A         cmp     bl, 7A 015A0070    77 03           ja      short 015A0075 015A0072    80EB 20         sub     bl, 20 015A0075    8A7F FF         mov     bh, [edi-1] 015A0078    80FF 61         cmp     bh, 61 015A007B    72 08           jb      short 015A0085 015A007D    80FF 7A         cmp     bh, 7A 015A0080    77 03           ja      short 015A0085 015A0082    80EF 20         sub     bh, 20 015A0085    38FB            cmp     bl, bh 015A0087  ^ 74 D8           je      short 015A0061 015A0089    0FB6C3          movzx   eax, bl 015A008C    0FB6D7          movzx   edx, bh 015A008F    29D0            sub     eax, edx 015A0091    5B              pop     ebx 015A0092    5F              pop     edi 015A0093    5E              pop     esi 015A0094    C3              retn 015A0095    C3              retn



    乍一看以为这个是壳里要处理什么东西,花指令跟别的地方也很像,试着跟踪看能不能找到原来的代码,可是这段代码
老老实实的走到了015A0094就直接返回程序里去了!那么这个就是我们要找的被偷的代码?可是看起来还不太像,这段代码
显然有着Aspr花指令的风格,于是仔细看了看这段指令,把它改一下,并分析:

代码:
015A0000    56              push    esi 015A0001    57              push    edi 015A0002    53              push    ebx 015A0003    8D744B 9A       lea     esi, [ebx+ecx*2-66] 015A0007    C1C6 1B         rol     esi, 1B 015A000A    C1C6 F7         rol     esi, 0F7 015A000D    8D7420 3C       lea     esi, [eax+3C] 015A0011    8D740E C4       lea     esi, [esi+ecx-3C] 015A0015    2BF1            sub     esi, ecx          //从015A003到这句其实就是mov esi,eax 015A0017    8D7C51 E7       lea     edi, [ecx+edx*2-19] 015A001B    EB 02           jmp     short 015A001F 015A001D    90              nop 015A001E    90              nop 015A001F    8D7C4B 16       lea     edi, [ebx+ecx*2+16] 015A0023    83EF 16         sub     edi, 16 015A0026    8D7C35 E3       lea     edi, [ebp+esi-1D] 015A002A    2BFE            sub     edi, esi 015A002C    8D7C0A 63       lea     edi, [edx+ecx+63] 015A0030    F3:             prefix rep: 015A0031    EB 02           jmp     short 015A0035 015A0033    90              nop 015A0034    90              nop 015A0035    2BF9            sub     edi, ecx 015A0037    EB 01           jmp     short 015A003A 015A0039    90              nop 015A003A    8D7F 9D         lea     edi, [edi-63]//从015A0017到这句其实就是mov edi,edx 015A003D    09C0            or      eax, eax 015A003F    74 03           je      short 015A0044 015A0041    8B40 FC         mov     eax, [eax-4] 015A0044    09D2            or      edx, edx 015A0046    74 03           je      short 015A004B 015A0048    8B52 FC         mov     edx, [edx-4] 015A004B    B9 4EE14A00     mov     ecx, 4AE14E 015A0050    B9 86C54000     mov     ecx, 40C586 015A0055    50              push    eax 015A0056    2BCD            sub     ecx, ebp 015A0058    59              pop     ecx      //从015A004B到这句其实就是mov eax,ecx 015A0059    39D1            cmp     ecx, edx 015A005B    76 02           jbe     short 015A005F 015A005D    89D1            mov     ecx, edx 015A005F    39C9            cmp     ecx, ecx 015A0061    F3:A6           repe    cmps byte ptr es:[edi], byte ptr [esi] 015A0063    74 2A           je      short 015A008F 015A0065    8A5E FF         mov     bl, [esi-1] 015A0068    80FB 61         cmp     bl, 61 015A006B    72 08           jb      short 015A0075 015A006D    80FB 7A         cmp     bl, 7A 015A0070    77 03           ja      short 015A0075 015A0072    80EB 20         sub     bl, 20 015A0075    8A7F FF         mov     bh, [edi-1] 015A0078    80FF 61         cmp     bh, 61 015A007B    72 08           jb      short 015A0085 015A007D    80FF 7A         cmp     bh, 7A 015A0080    77 03           ja      short 015A0085 015A0082    80EF 20         sub     bh, 20 015A0085    38FB            cmp     bl, bh 015A0087  ^ 74 D8           je      short 015A0061 015A0089    0FB6C3          movzx   eax, bl 015A008C    0FB6D7          movzx   edx, bh 015A008F    29D0            sub     eax, edx 015A0091    5B              pop     ebx 015A0092    5F              pop     edi 015A0093    5E              pop     esi 015A0094    C3              retn



    这个函数应该是Delphi的一个比较字符串的函数,看来的确是被偷的那段代码,不过他已经被壳改的很乱,不可能贴回到
原来位置了,只好在程序代码段后面找一块地方,把它贴上:

代码:
0045AF66    0000            add     [eax], al 0045AF68    0000            add     [eax], al 0045AF6A    56              push    esi 0045AF6B    57              push    edi 0045AF6C    53              push    ebx ......... ......... 0045AFF3    0FB6C3          movzx   eax, bl 0045AFF6    0FB6D7          movzx   edx, bh 0045AFF9    29D0            sub     eax, edx 0045AFFB    5B              pop     ebx 0045AFFC    5F              pop     edi 0045AFFD    5E              pop     esi 0045AFFE    C3              retn 0045AFFF    00              ???                                                     ; 命令置于内存块尾



    之后再把00407FDC处改一下,跳过来:

代码:
00407FDC   /E9 892F0500     jmp     0045AF6A 00407FE1   |C3              retn 00407FE2   |B7 68           mov     bh, 68



    然后保存修改到文件中,运行一下。终于OK了。
    
四、后记
    
    感谢你这么有耐心得看完这篇文章,希望对你有帮助。在这里更要感谢论坛里的牛人们,无数牛人的文章使我受益良多。

    关于那段stolen code,其实这段代码可以恢复成和原来一样的,但是如果没有原来的代码我想很难分析出来,上面的分析
我也是照着我的源码分析的,联系到今后更多的情况时未知源码的,这种贴回来的方法更实用。