这是某游戏辅助软件的一个主要dll文件,由于想diy其中的某个功能,所以必须先脱壳。我学破解也有一段时间了,但正儿八经的脱壳还是第一次,不怕大伙笑话,我前后花在脱这个壳的时间加起来快半个月了,当前其中也包括很多学习的过程,下面我把脱壳的过程记录下来,希望对和我一样的新手有所帮助。
这是个10kb的dll文件,作者擅长asm,所以肯定是asm编写的。有antidebug,具体机理不知。
PEID检测结果:
普通扫描
PackMan v0.0.0.1 *
深度扫描
UPX 0.80 - 1.24 DLL -> Markus & Laszlo
核心扫描
UPX 0.80 - 1.24 DLL -> Markus & Laszlo
=============================
DIE核心探测也可以检测出压缩过,提示的是:
--> UPX 0.9x - 3.0
而首页的显示
Microsoft Visual C++ | C/C++
External Sign:Packman v0.0.0.1
初步判断是加了2层壳,PackMan v0.0.0.1和UPX 0.80 - 1.24,好,OD加载strongOD插件,选项全选(其实我也不清楚很多选项的作用,但能过反调试就行了)后载入dll,停在以下位置:
代码:
1000C098 > 60 PUSHAD 1000C099 E8 00000000 CALL k.1000C09E 1000C09E 58 POP EAX 1000C09F 8DA8 6AFFFFFF LEA EBP,DWORD PTR DS:[EAX-96]
BP GetModuleHandleA在它处理输入表之前断下,返回到程序领空,这时候用loadpe把程序内存完全dump出来
代码:
1000C184 56 PUSH ESI ;ESI=1000B000,输入表RVA=1000B000-10000000=B000 1000C185 8B36 MOV ESI,DWORD PTR DS:[ESI] 1000C187 0BF6 OR ESI,ESI 1000C189 75 02 JNZ SHORT k.1000C18D 1000C18B 8BF7 MOV ESI,EDI .... 1000C1B4 5E POP ESI 1000C1B5 83C6 14 ADD ESI,14 1000C1B8 8B7E 10 MOV EDI,DWORD PTR DS:[ESI+10] 1000C1BB 85FF TEST EDI,EDI 1000C1BD ^ 75 BC JNZ SHORT k.1000C17B ;到这里输入表处理完毕 1000C1BF 8D8B 000000F0 LEA ECX,DWORD PTR DS:[EBX+F0000000];直接跳过循环执行到这里,开始处理重定位表,这时候ESI=1000B028,输入表大小为B028-B000=28 1000C1C5 B8 94B00000 MOV EAX,0B094 ;B094就是重定位表的RVA 1000C1CA 0BC0 OR EAX,EAX 1000C1CC 74 34 JE SHORT k.1000C202 ;重定位表处理完跳到1000C202 .... 1000C1FE 85FF TEST EDI,EDI 1000C200 ^ 75 D0 JNZ SHORT k.1000C1D2 1000C202 61 POPAD ;重定位表处理完到这里,我们直接跳到这里看看重定位表有多大,ESI=1000B0A0,那么重定位表大小就是B0A0-B094=C(这么小是因为里面还有一层壳) 1000C203 ^ E9 90FEFFFF JMP k.<ModuleEntryPoint> 1000C098 >- E9 B3E1FFFF JMP k.1000A250 ;OEP=1000A250
用pe编辑器修改刚才的到dump文件,得到脱掉第一层的文件,测试能正常运行。
peid扫描这个文件UPX 0.80 - 1.24 DLL -> Markus & Laszlo
说明还有一层UPX的壳,由于只有2个txt区段,说明这不是upx的标准区段,被作者修改过,自然不能用UPX -d直接脱壳,在这里我废了好大功夫,试了各种upx修复工具修复区段都没成功,脱壳机也试了不少还是不行,看来还是得手工脱,仔细研究了《加密与解密第三版》345页的脱壳过程,最终得到了完美的基本与原文件相同的脱壳文件。
UPX的壳oep很好找,直接往下拉拉就看到了去OEP的跳转。
代码:
1000A3A6 > \83C7 04 ADD EDI,4 1000A3A9 . 8D5E FC LEA EBX,DWORD PTR DS:[ESI-4] 1000A3AC > 31C0 XOR EAX,EAX ; 处理重定位表开始 1000A3AE . 8A07 MOV AL,BYTE PTR DS:[EDI] 1000A3B0 . 47 INC EDI 1000A3B1 . 09C0 OR EAX,EAX ; 检测是否为0,否则结束重定位 1000A3B3 . 74 22 JE SHORT 脱掉第一.1000A3D7 1000A3B5 . 3C EF CMP AL,0EF 1000A3B7 . 77 11 JA SHORT 脱掉第一.1000A3CA 1000A3B9 > 01C3 ADD EBX,EAX 1000A3BB . 8B03 MOV EAX,DWORD PTR DS:[EBX] ; EBX指向需要重定位的数据,取出放到EAX 1000A3BD . 86C4 XCHG AH,AL 1000A3BF . C1C0 10 ROL EAX,10 1000A3C2 . 86C4 XCHG AH,AL 1000A3C4 . 01F0 ADD EAX,ESI ; ESI指向第一区段VA,这里是10001000 1000A3C6 . 8903 MOV DWORD PTR DS:[EBX],EAX ; 重定位 1000A3C8 .^ EB E2 JMP SHORT 脱掉第一.1000A3AC 1000A3CA > 24 0F AND AL,0F 1000A3CC . C1E0 10 SHL EAX,10 1000A3CF . 66:8B07 MOV AX,WORD PTR DS:[EDI] 1000A3D2 . 83C7 02 ADD EDI,2 1000A3D5 .^ EB E2 JMP SHORT 脱掉第一.1000A3B9 ; 处理重定位表结束 1000A3D7 > 61 POPAD 1000A3D8 >^ E9 D18CFFFF JMP 脱掉第一.100030AE ; 跳往OEP .... 100030AE 55 PUSH EBP ;OEP 100030AF 8BEC MOV EBP,ESP 100030B1 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C] 100030B4 83F8 01 CMP EAX,1 100030B7 75 14 JNZ SHORT 脱掉第一.100030CD 100030B9 60 PUSHAD 100030BA E8 1E040000 CALL 脱掉第一.100034DD

整理文件头区段信息,把它还原那么应该是这样:

参考这些信息,我们现在重新构造这个dll文件。用winhex新建一个空白的文件,大小为5600h
按ctrl+B把dump文件的1000h开始到41CBh结束处的hex拷贝到新文件的400h处,这样text区段就准备好了。6000h到755Ah为data段,拷贝到新文件的3800处。93EDh到9584h为部分文件头,拷贝到40h(你也可以拷贝到50h,反正最终dos header里要设定)。输入表很简单,用ImportREC_fix或者自己手写都可以,写入到3600h,我偷懒是用ImportREC_fix修复的。
下面是dos header,其实dos header真的很简单,只要写入两个地方,一个是magic number,就是字符MZ,写在hex文件里是4D5A;还有最后一个file address of new exe header,就写刚才我们设好的40h,写在hex文件里就是40000000。其他都留空。
如下:
[

最后是最麻烦的重定位表,由于imagebase设定死了10000000所以不能用常规方法那样用Dll_LoadEx加载两个相同dll得到reloc table。还是要手工修复,我用论坛上有个大牛写的脚本,我得到的重定位表不对,翻开书静静的看了半小时,开始修复:
先在OD里写代码处理重定位的RVA:

一定要记得把内存1000A400处的数据改成1000A410,否则代码无法执行:

在100030B9处下断点,F9运行,我们看在我们指定的内存中出现了需要重定位的RVA:
.jpg)
从1000A410处拷贝生成的RVA序列二进制文件到winhex中,保存。然后用拽到reloRec中生成重定位表,写入刚才新建的文件8000h处。
忐忑不安的运行自己构建的文件,看来一切ok,有种苦尽甘来的感觉,希望与您分享。