一、破解目标:PE-Armor 0.7x 加壳的DLL

二、破解工具:OllyDbg v1.10,ImportREC 1.6 Final,LordPE

三、破解作者:DarkBull@email.com.cn

四、破解过程:

1.简单分析

壳使用了大量的SEH和花指令,用DRX解码,用NT Native API和RTDSC指令反跟踪,论坛上有很多相关的文章可供参考学习,这里不再遨述。

01601BD9 >  60          PUSHAD                                 ; 入口仿yoda's cryptor 1.2
01601BDA    E8 00000000 CALL 01601BDF
01601BDF    5D          POP EBP
01601BE0    81ED F31D40>SUB EBP,401DF3
01601BE6    B9 7B090000 MOV ECX,97B
01601BEB    8DBD 3B1E40>LEA EDI,DWORD PTR SS:[EBP+401E3B]
01601BF1    8BF7        MOV ESI,EDI
01601BF3    AC          LODSB
01601BF4    61          POPAD
01601BF5  ^ E9 D7F4FEFF JMP 015F10D1

用看雪老大的HideOD隐藏OllyDbg,忽略所有异常,在第一个段下内存访问断点,见解压代码如下:

0006F8E2    AC          LODSB                                  ; 读一个字节
0006F8E3    D2C8        ROR AL,CL
0006F8E5    30C8        XOR AL,CL
0006F8E7    04 65       ADD AL,65
0006F8E9    30E8        XOR AL,CH
0006F8EB    00F0        ADD AL,DH
0006F8ED    28D0        SUB AL,DL
0006F8EF    00C8        ADD AL,CL
0006F8F1    28E8        SUB AL,CH
0006F8F3    30D0        XOR AL,DL
0006F8F5    04 23       ADD AL,23
0006F8F7    30F0        XOR AL,DH
0006F8F9    F6D0        NOT AL
0006F8FB    D2C8        ROR AL,CL
0006F8FD    D3CA        ROR EDX,CL
0006F8FF    8846 FF     MOV BYTE PTR DS:[ESI-1],AL              ; 写入解压后的代码
0006F902    49          DEC ECX
0006F903  ^ 75 DD       JNZ SHORT 0006F8E2
0006F905    5A          POP EDX
0006F906    C3          RET

执行完后,壳分配一块内存空间,然后再次解压代码。

2.修复IAT

下断点BP GetModuleHandleW,拦截后查找常数79797979,见如下代码:

003D79F2    BE 79797979 MOV ESI,79797979                        ; Patch1
003D79F7    8BF0        MOV ESI,EAX
003D79F9    0BC9        OR ECX,ECX
003D79FB    0F85 620700>JNZ 003D8163                            ; 是否HOOK API

没有被HOOK的函数名解压代码如下:

003D7E61    33C0        XOR EAX,EAX                             ; JMP Patch2
003D7E63    AC          LODSB
003D7E64    EB 07       JMP SHORT 003D7E6D
003D7E66    C0C0 03     ROL AL,3
003D7E69    F6D0        NOT AL
003D7E6B    AA          STOSB
003D7E6C    AC          LODSB
003D7E6D    0BC0        OR EAX,EAX
003D7E6F  ^ 75 F5       JNZ SHORT 003D7E66
003D7E71    AA          STOSB

被HOOK的函数名解压代码(在堆栈里)如下:

0006F8CC    50          PUSH EAX 
0006F8CD    AC          LODSB
0006F8CE    34 79       XOR AL,79
0006F8D0    2C 55       SUB AL,55
0006F8D2    C0C0 03     ROL AL,3
0006F8D5    F6D0        NOT AL
0006F8D7    AA          STOSB
0006F8D8    31C0        XOR EAX,EAX
0006F8DA    49          DEC ECX
0006F8DB  ^ 75 F0       JNZ SHORT 0006F8CD
0006F8DD    AA          STOSB

Patch1的代码如下:

003D79F2    FF32        PUSH DWORD PTR DS:[EDX]
003D79F4    8F05 30353E>POP DWORD PTR DS:[3E3530]
003D79FA    8BF0        MOV ESI,EAX
003D79FC    0FB60A      MOVZX ECX,BYTE PTR DS:[EDX]
003D79FF    90          NOP
003D7A00    90          NOP
003D7A01    90          NOP
003D7A02    90          NOP

Patch2的代码如下:

003E3500    A1 30353E00 MOV EAX,DWORD PTR DS:[3E3530]
003E3505    25 00000080 AND EAX,80000000
003E350A    74 19       JE SHORT 003E3525                       ; 是否为被HOOK的函数
003E350C    AC          LODSB
003E350D    08C0        OR AL,AL
003E350F    74 0C       JE SHORT 003E351D
003E3511    34 79       XOR AL,79
003E3513    2C 55       SUB AL,55
003E3515    C0C0 03     ROL AL,3
003E3518    F6D0        NOT AL
003E351A    AA          STOSB
003E351B  ^ EB EF       JMP SHORT 003E350C
003E351D    33C0        XOR EAX,EAX
003E351F    AA          STOSB
003E3520  ^ E9 4D49FFFF JMP 003D7E72
003E3525    33C0        XOR EAX,EAX                             ; 走原路线
003E3527    AC          LODSB
003E3528  ^ E9 4049FFFF JMP 003D7E6D

壳的GetProcAddress如下:

003E0858 >  55          PUSH EBP
003E0859    8BEC        MOV EBP,ESP
003E085B    83C4 F4     ADD ESP,-0C
003E085E    60          PUSHAD
003E085F    8B75 08     MOV ESI,DWORD PTR SS:[EBP+8]
003E0862    0BF6        OR ESI,ESI
003E0864    75 0E       JNZ SHORT 003E0874
003E0866    64:A1 18000>MOV EAX,DWORD PTR FS:[18]
003E086C    8B40 30     MOV EAX,DWORD PTR DS:[EAX+30]
003E086F    8B40 08     MOV EAX,DWORD PTR DS:[EAX+8]
003E0872    8BF0        MOV ESI,EAX
003E0874    8BC6        MOV EAX,ESI
003E0876    8BD8        MOV EBX,EAX
003E0878    8BC8        MOV ECX,EAX
003E087A    8BD0        MOV EDX,EAX
003E087C    8BF8        MOV EDI,EAX
003E087E    66:8138 4D5>CMP WORD PTR DS:[EAX],5A4D              ; IMAGE_DOS_SIGNATURE 
003E0883    74 05       JE SHORT 003E088A
003E0885    E9 94000000 JMP 003E091E
003E088A    0349 3C     ADD ECX,DWORD PTR DS:[ECX+3C]           ; PE Header
003E088D    8379 78 00  CMP DWORD PTR DS:[ECX+78],0             ; IMAGE_EXPORT_DIRECTORY的RVA
003E0891    75 05       JNZ SHORT 003E0898
003E0893    E9 86000000 JMP 003E091E
003E0898    0371 78     ADD ESI,DWORD PTR DS:[ECX+78]
003E089B    8975 F8     MOV DWORD PTR SS:[EBP-8],ESI
003E089E    8BC6        MOV EAX,ESI
003E08A0    0341 7C     ADD EAX,DWORD PTR DS:[ECX+7C]
003E08A3    8945 F4     MOV DWORD PTR SS:[EBP-C],EAX
003E08A6    8B45 08     MOV EAX,DWORD PTR SS:[EBP+8]
003E08A9    0346 1C     ADD EAX,DWORD PTR DS:[ESI+1C]
003E08AC    8945 FC     MOV DWORD PTR SS:[EBP-4],EAX
003E08AF    817D 0C 000>CMP DWORD PTR SS:[EBP+C],10000
003E08B6    76 35       JBE SHORT 003E08ED
003E08B8    8B4E 18     MOV ECX,DWORD PTR DS:[ESI+18]
003E08BB    0356 24     ADD EDX,DWORD PTR DS:[ESI+24]
003E08BE    037E 20     ADD EDI,DWORD PTR DS:[ESI+20]
003E08C1    EB 1E       JMP SHORT 003E08E1
003E08C3    8B07        MOV EAX,DWORD PTR DS:[EDI]
003E08C5    0345 08     ADD EAX,DWORD PTR SS:[EBP+8]
003E08C8    FF75 0C     PUSH DWORD PTR SS:[EBP+C]               ; 要查找地址的函数
003E08CB    50          PUSH EAX                                ; 从第一个引出函数开始
003E08CC    E8 D1000000 CALL 003E09A2                           ; 枚举函数
003E08D1    0BC0        OR EAX,EAX
003E08D3    75 05       JNZ SHORT 003E08DA
003E08D5    0FB702      MOVZX EAX,WORD PTR DS:[EDX]
003E08D8    EB 0B       JMP SHORT 003E08E5
003E08DA    83C7 04     ADD EDI,4
003E08DD    83C2 02     ADD EDX,2
003E08E0    49          DEC ECX
003E08E1    0BC9        OR ECX,ECX
003E08E3  ^ 75 DE       JNZ SHORT 003E08C3
003E08E5    0BC9        OR ECX,ECX
003E08E7    75 11       JNZ SHORT 003E08FA
003E08E9    EB 33       JMP SHORT 003E091E
003E08EB    EB 0D       JMP SHORT 003E08FA
003E08ED    8B45 0C     MOV EAX,DWORD PTR SS:[EBP+C]
003E08F0    2B46 10     SUB EAX,DWORD PTR DS:[ESI+10]
003E08F3    3B46 14     CMP EAX,DWORD PTR DS:[ESI+14]
003E08F6    76 02       JBE SHORT 003E08FA
003E08F8    EB 24       JMP SHORT 003E091E
003E08FA    8B5D FC     MOV EBX,DWORD PTR SS:[EBP-4]
003E08FD    8B0483      MOV EAX,DWORD PTR DS:[EBX+EAX*4]
003E0900    0345 08     ADD EAX,DWORD PTR SS:[EBP+8]            ; 得到函数地址
003E0903    3B45 F8     CMP EAX,DWORD PTR SS:[EBP-8]
003E0906    76 0B       JBE SHORT 003E0913
003E0908    3B45 F4     CMP EAX,DWORD PTR SS:[EBP-C]
003E090B    73 06       JNB SHORT 003E0913
003E090D    50          PUSH EAX
003E090E    E8 12000000 CALL 003E0925
003E0913    8945 FC     MOV DWORD PTR SS:[EBP-4],EAX
003E0916    61          POPAD
003E0917    8B45 FC     MOV EAX,DWORD PTR SS:[EBP-4]
003E091A    C9          LEAVE
003E091B    C2 0800     RET 8
003E091E    61          POPAD
003E091F    33C0        XOR EAX,EAX
003E0921    C9          LEAVE
003E0922    C2 0800     RET 8

壳处理完全部IAT后,用ImportREC可获得完整的IAT。

3.修复Reloc Table

壳处理地址重定位的代码如下:

003DD5CD    0FB606      MOVZX EAX,BYTE PTR DS:[ESI]             ; 读加密后的重定位表
003DD5D0    EB 2F       JMP SHORT 003DD601
003DD5D2    3C 01       CMP AL,1                                ; 是否为1
003DD5D4    75 15       JNZ SHORT 003DD5EB
003DD5D6    46          INC ESI
003DD5D7    0FB606      MOVZX EAX,BYTE PTR DS:[ESI]
003DD5DA    3C 02       CMP AL,2 
003DD5DC    75 08       JNZ SHORT 003DD5E6
003DD5DE    46          INC ESI
003DD5DF    031E        ADD EBX,DWORD PTR DS:[ESI]
003DD5E1    83C6 04     ADD ESI,4
003DD5E4    EB 18       JMP SHORT 003DD5FE
003DD5E6    46          INC ESI
003DD5E7    03D8        ADD EBX,EAX
003DD5E9    EB 13       JMP SHORT 003DD5FE
003DD5EB    3C 02       CMP AL,2                                ; 是否为2                         
003DD5ED    75 0A       JNZ SHORT 003DD5F9
003DD5EF    46          INC ESI
003DD5F0    031E        ADD EBX,DWORD PTR DS:[ESI]
003DD5F2    013B        ADD DWORD PTR DS:[EBX],EDI              ; 地址重定位
003DD5F4    83C6 04     ADD ESI,4
003DD5F7    EB 05       JMP SHORT 003DD5FE
003DD5F9    46          INC ESI                                 ; 缺省方式
003DD5FA    03D8        ADD EBX,EAX
003DD5FC    013B        ADD DWORD PTR DS:[EBX],EDI              ; 地址重定位
003DD5FE    0FB606      MOVZX EAX,BYTE PTR DS:[ESI]
003DD601    0AC0        OR AL,AL
003DD603  ^ 75 CD       JNZ SHORT 003DD5D2

重定位从模块的基址开始,如果为1则重定位表的指针加1,为2则重定位地址加上读出的4个字节数字,缺省加上读出的1个字节数字。

写一段还原Reloc Table的代码如下:

00401000 > $  60        PUSHAD
00401001   .  33C0      XOR EAX,EAX
00401003   .  33C9      XOR ECX,ECX
00401005   .  33D2      XOR EDX,EDX
00401007   .  33DB      XOR EBX,EBX
00401009   .  33ED      XOR EBP,EBP
0040100B   .  BE 00005C>MOV ESI,15C0000                         ; 加密后的重定位表
00401010   .  BF 000074>MOV EDI,1740000                         ; 自己分配一块空间
00401015   >  0FB606    MOVZX EAX,BYTE PTR DS:[ESI]             ; 读加密后的重定位表
00401018   .  0AC0      OR AL,AL
0040101A   .  74 68     JE SHORT 00401084
0040101C   .  3C 02     CMP AL,2                                ; 因为调试时没有等于1的情况
0040101E   .  75 08     JNZ SHORT 00401028
00401020   .  46        INC ESI
00401021   .  031E      ADD EBX,DWORD PTR DS:[ESI]
00401023   .  83C6 04   ADD ESI,4
00401026   .  EB 03     JMP SHORT 0040102B
00401028   >  03D8      ADD EBX,EAX                             ; 不等于2
0040102A   .  46        INC ESI
0040102B   >  8BCB      MOV ECX,EBX
0040102D   .  81E1 00F0>AND ECX,FFFFF000
00401033   .  3BCA      CMP ECX,EDX
00401035   .  74 3D     JE SHORT 00401074                       ; 是否为新的一节
00401037   .  50        PUSH EAX
00401038   .  51        PUSH ECX
00401039   .  52        PUSH EDX
0040103A   .  8BC7      MOV EAX,EDI
0040103C   .  33D2      XOR EDX,EDX
0040103E   .  B9 040000>MOV ECX,4
00401043   .  F7F1      DIV ECX
00401045   .  84D2      TEST DL,DL
00401047   .  74 03     JE SHORT 0040104C                       ; 每一节以4字节对齐
00401049   .  83C7 02   ADD EDI,2
0040104C   >  5A        POP EDX
0040104D   .  59        POP ECX
0040104E   .  58        POP EAX
0040104F   .  890F      MOV DWORD PTR DS:[EDI],ECX              ; 写入每一节的RVA
00401051   .  8BD1      MOV EDX,ECX
00401053   .  85ED      TEST EBP,EBP
00401055   .  74 08     JE SHORT 0040105F
00401057   .  8BC7      MOV EAX,EDI
00401059   .  2BC5      SUB EAX,EBP
0040105B   .  3E:8945 0>MOV DWORD PTR DS:[EBP+4],EAX            ; 写入每一节大小
0040105F   >  8BEF      MOV EBP,EDI
00401061   .  83C7 08   ADD EDI,8
00401064   .  8BC3      MOV EAX,EBX
00401066   .  25 FF0F00>AND EAX,0FFF
0040106B   .  0D 003000>OR EAX,3000
00401070   .  66:AB     STOS                                    ; 写入类型和地址
00401072   .^ EB A1     JMP SHORT 00401015
00401074   >  8BC3      MOV EAX,EBX
00401076   .  25 FF0F00>AND EAX,0FFF
0040107B   .  0D 003000>OR EAX,3000
00401080   .  66:AB     STOS                                    ; 写入类型和地址
00401082   .^ EB 91     JMP SHORT 00401015
00401084   >  8BC7      MOV EAX,EDI
00401086   .  33D2      XOR EDX,EDX
00401088   .  B9 040000>MOV ECX,4
0040108D   .  F7F1      DIV ECX
0040108F   .  84D2      TEST DL,DL
00401091   .  74 03     JE SHORT 00401096                       ; 每一节以4字节对齐
00401093   .  83C7 02   ADD EDI,2
00401096   >  8BC7      MOV EAX,EDI
00401098   .  2BC5      SUB EAX,EBP
0040109A   .  3E:8945 0>MOV DWORD PTR DS:[EBP+4],EAX            ; 写入每一节大小
0040109E   .  61        POPAD

执行完后,就可以得到大部分的Reloc Table,剩下的一小部分(这里是5个)是被偷的OEP用的,只好手动还原了。

4.还原OEP

通过最后一个异常(Array bounds exceeded),很快就到变形的OEP了,代码如下:

003E335F    FFF5        PUSH EBP                                ; OEP
003E3361    EB 03       JMP SHORT 003E3366
003E3363    4F          DEC EDI
003E3364    64:CF       IRETD 
003E3366    54          PUSH ESP
003E3367    5D          POP EBP                                 ; MOV EBP,ESP
003E3368    EB 00       JMP SHORT 003E336A
003E336A    54          PUSH ESP
003E336B    830424 C4   ADD DWORD PTR SS:[ESP],-3C              ; ADD ESP,-3C
003E336F    5C          POP ESP
003E3370    EB 03       JMP SHORT 003E3375
003E3372    59          POP ECX
003E3373    64:CF       IRETD
003E3375    68 70779500 PUSH 957770
003E337A    58          POP EAX                                 ; MOV EAX,957770
003E337B    EB 03       JMP SHORT 003E3380
003E337D    AA          STOSB
003E337E    64:CF       IRETD
003E3380    E8 02000000 CALL 003E3387
003E3385    EB 11       JMP SHORT 003E3398
003E3387    50          PUSH EAX
003E3388    E8 04000000 CALL 003E3391
........
003E3391    58          POP EAX
003E3392    8B00        MOV EAX,DWORD PTR DS:[EAX]
003E3394    870424      XCHG DWORD PTR SS:[ESP],EAX
003E3397    C3          RET                                     ; 到原程序的第一个PROC
........

跟一下就能还原OEP了,壳把原来的OEP全部清零,手动添加后,即可DUMP。