一、破解目标: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。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)