forgot的unpackme 1.7yyy的脱壳
日期:2005年3月13日 脱壳人:csjwaman[DFCG]
――――――――――――――――――――――――――――――――――――――――――― 【软件名称】:forgot的unpackme 1.7yyy
【下载地址】:见附件。
【脱壳声明】:初学Crack,只是感兴趣,没有其它目的。失误之处敬请诸位大侠赐教!
【操作系统】:winxp
【脱壳工具】:OD等传统工具
―――――――――――――――――――――――――――――――――――――――――――
【脱壳过程】: forgot说:有的壳脱了,它还活着。
Lenus说:有的壳没脱,他已经死了:)
下面就看看这壳是怎么死的:)
第一步,找d-process处:
用OD载入程序,忽略所有异常,bp WriteProcessMemory,F9运行程序,断下:
77E41A94 k> 55 push ebp////断下。取消断点(我习惯及时取消断点,这样可以避免一些不必要的麻烦。)。
77E41A95 8BEC mov ebp,esp
77E41A97 51 push ecx
77E41A98 51 push ecx
77E41A99 8B45 0C mov eax,dword ptr ss:[ebp+C]
77E41A9C 53 push ebx
77E41A9D 8B5D 14 mov ebx,dword ptr ss:[ebp+14]
77E41AA0 56 push esi
77E41AA1 8B35 B012E477 mov esi,dword ptr ds:[<&ntdll.N>; ntdll.ZwProtectVirtualMemory
77E41AA7 57 push edi 观察堆栈数据:
003C7054 003CB1A7 /CALL 到 WriteProcessMemory 来自 003CB1A2
003C7058 00000034 |hProcess = 00000034 (window)
003C705C 003CC8B4 |Address = 3CC8B4////重要!记下备用。
003C7060 003CC223 |Buffer = 003CC223
003C7064 0000029A |BytesToWrite = 29A (666.)////重要!记下备用。
003C7068 00000000 \pBytesWritten = NULL
好,F9直接运行程序,等出现界面时,运行LordPE选中映像文件小的那个进程,然后部分DUMP,把从3CC8B4处开始大小为29A的数据DUMP下来,命名为3CC8B4.bin。
第二步,变双进程为单进程:
重新载入程序,bp CreateProcessA,运行程序,断下:
77E41BBC k> 55 push ebp////断下。取消断点。
77E41BBD 8BEC mov ebp,esp
77E41BBF 6A 00 push 0
77E41BC1 FF75 2C push dword ptr ss:[ebp+2C]
77E41BC4 FF75 28 push dword ptr ss:[ebp+28]
77E41BC7 FF75 24 push dword ptr ss:[ebp+24]
77E41BCA FF75 20 push dword ptr ss:[ebp+20] 观察堆栈数据:
003C7040 003CA08A /CALL 到 CreateProcessA 来自 003CA085
003C7044 003C8DF7 |ModuleFileName = "C:\Documents and Settings\csjwaman\桌面\17y.rar_828\1.exe"
003C7048 003CA07B |CommandLine = "X"////调试标志。
003C704C 00000000 |pProcessSecurity = NULL
003C7050 00000000 |pThreadSecurity = NULL
003C7054 00000000 |InheritHandles = FALSE
003C7058 00000003 |CreationFlags = DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS
003C705C 00000000 |pEnvironment = NULL
003C7060 00000000 |CurrentDir = NULL
003C7064 003C73CC |pStartupInfo = 003C73CC
003C7068 003C73BC \pProcessInfo = 003C73BC 重新载入程序,bp GetCommandLineA,运行程序,断下:
77E5E358 k> A1 1476EB77 mov eax,dword ptr ds:[77EB7614]////断在这里。取消断点。
77E5E35D C3 retn
返回到:
003C81DA 68 9F6F56B6 push B6566F9F////返回到这里。
003C81DF 50 push eax
003C81E0 E8 5D000000 call 003C8242
003C81E5 EB FF jmp short 003C81E6
003C81E7 71 78 jno short 003C8261
003C81E9 C2 5000 retn 50
003C81EC ^ EB D3 jmp short 003C81C1 搜索二进制字符“803e58”,找到:
003C8475 ^\71 EB jno short 003C8462
003C8477 ^ EB FA jmp short 003C8473
003C8479 ^ EB 80 jmp short 003C83FB/////找到这里。这里有个花指令。
003C847B 3E:58 pop eax
003C847D 0F84 8A410000 je 003CC60D////在此F2断下后,取消断点,然后改Z标志位让跳!可以变为单进程。 第三步,修补程序:
修改上面这个跳转后,用十六进制工具把3CC8B4.bin的数据复盖掉OD的DUMP区从003CC8B4处开始的29A个字节数据。
第四步,修复IAT及查找入口:
做完上述工作后,在OD的CPU窗口,Ctrl+G,输入003CC8B4,点确定后来到:
003CC8AB ^\71 EB jno short 003CC898
003CC8AD ^ EB FA jmp short 003CC8A9
003CC8AF ^ EB F0 jmp short 003CC8A1////NOP掉。
003CC8B1 0FC7C8 cmpxchg8b eax ////NOP掉。
003CC8B4 FFC3 inc ebx/////来到这里。
003CC8B6 FFC8 dec eax
003CC8B8 F7D8 neg eax
003CC8BA F7C1 2DF16825 test ecx,2568F12D
003CC8C0 8BD9 mov ebx,ecx
003CC8C2 01CB add ebx,ecx
003CC8C4 85CB test ebx,ecx
003CC8C6 8BDA mov ebx,edx 在003CC8B4处硬件执行断点,F9断下后取消断点!恢复刚才NOP掉的代码。
然后直接往下找,来到:
003CF7AF 8B8D 63D54000 mov ecx,dword ptr ss:[ebp+40D563]
003CF7B5 0349 3C add ecx,dword ptr ds:[ecx+3C]
003CF7B8 8B41 50 mov eax,dword ptr ds:[ecx+50]
003CF7BB 0385 63D54000 add eax,dword ptr ss:[ebp+40D563]
003CF7C1 8B8D 63D54000 mov ecx,dword ptr ss:[ebp+40D563]
003CF7C7 81C1 00100000 add ecx,1000
003CF7CD 8BBD 63D54000 mov edi,dword ptr ss:[ebp+40D563]
003CF7D3 037F 3C add edi,dword ptr ds:[edi+3C]
003CF7D6 8B7F 1C mov edi,dword ptr ds:[edi+1C]
003CF7D9 03BD 63D54000 add edi,dword ptr ss:[ebp+40D563]
003CF7DF 81C7 00100000 add edi,1000
003CF7E5 66:8139 FF25 cmp word ptr ds:[ecx],25FF
003CF7EA 74 02 je short 003CF7EE////这里开始处理IAT跳转表。改为JMP 003CF82B。
003CF7EC EB 05 jmp short 003CF7F3
003CF7EE 3941 02 cmp dword ptr ds:[ecx+2],eax
003CF7F1 72 07 jb short 003CF7FA
003CF7F3 41 inc ecx
003CF7F4 3BCF cmp ecx,edi
003CF7F6 ^ 72 ED jb short 003CF7E5
003CF7F8 EB 27 jmp short 003CF821
003CF7FA 8B59 02 mov ebx,dword ptr ds:[ecx+2]
003CF7FD 8B1B mov ebx,dword ptr ds:[ebx]
003CF7FF C601 68 mov byte ptr ds:[ecx],68////IAT跳转改为PUSH xxxxxxxx,然后再RETN的形式。
003CF802 8959 01 mov dword ptr ds:[ecx+1],ebx
003CF805 C641 05 C3 mov byte ptr ds:[ecx+5],0C3////RETN
003CF809 83C1 06 add ecx,6
003CF80C 66:8139 FF25 cmp word ptr ds:[ecx],25FF
003CF811 75 04 jnz short 003CF817
003CF813 3BCF cmp ecx,edi
003CF815 ^ 72 CE jb short 003CF7E5
003CF817 83C1 02 add ecx,2
003CF81A 66:8139 FF25 cmp word ptr ds:[ecx],25FF
003CF81F ^ 74 D9 je short 003CF7FA
003CF821 83C1 24 add ecx,24
003CF824 66:8139 FF25 cmp word ptr ds:[ecx],25FF
003CF829 ^ 74 CF je short 003CF7FA
003CF82B 61 popad////下硬件执行断点,然后SHIFT+F9,通过几次异常后会断在这里,然后取消断点。
003CF82C E8 0A84FFFF call 003C7C3B
003CF831 68 9F6F56B6 push B6566F9F
003CF836 50 push eax
003CF837 E8 5D000000 call 003CF899
003CF83C EB FF jmp short 003CF83D
003CF83E 71 78 jno short 003CF8B8
003CF840 C2 5000 retn 50
跳转表处理和1.7xxx一样都改成 PUSH XXXXXXXX 然后 RETN 的形式!
跳过IAT加密后,继续直接往下找:
003CFDEB ^\71 EB jno short 003CFDD8
003CFDED ^ EB FA jmp short 003CFDE9
003CFDEF ^ EB 83 jmp short 003CFD74
003CFDF1 C017 EB rcl byte ptr ds:[edi],0EB
003CFDF4 FF70 ED push dword ptr ds:[eax-13]
003CFDF7 ^ 71 EB jno short 003CFDE4
003CFDF9 ^ EB FA jmp short 003CFDF5
003CFDFB EB 50 jmp short 003CFE4D
003CFDFD 8D78 02 lea edi,dword ptr ds:[eax+2]
003CFE00 EB 02 jmp short 003CFE04下硬件执行断点,F9,断下后取消断点。
003CFE02 61 popad
003CFE03 50 push eax
003CFE04 C3 retn////返回入口!
003CFE05 0200 add al,byte ptr ds:[eax]
003CFE07 0000 add byte ptr ds:[eax],al 在0032FDFF处断下后,EAX=403A3F,这就是入口地址。
00403A3F FFD7 call edi ; 1.00403A41////返回到这里。入口代码被修改了。
00403A41 58 pop eax
00403A42 90 nop
00403A43 90 nop
00403A44 E8 5B9B0000 call 1.0040D5A4 ; jmp to comdlg32.GetOpenFileNameA
00403A49 85C0 test eax,eax
00403A4B 74 17 je short 1.00403A64
00403A4D 68 15F14000 push 1.0040F115
00403A52 E8 2C000000 call 1.00403A83
00403A57 8B0D 04F04000 mov ecx,dword ptr ds:[40F004]
00403A5D E3 05 jecxz short 1.00403A64
00403A5F E8 229B0000 call 1.0040D586 ; jmp to kernel32.GlobalFree
00403A64 E8 059B0000 call 1.0040D56E ; jmp to kernel32.ExitProcess
00403A69 55 push ebp 到入口后观察堆栈区:
003C7440 0040F038 1.0040F038////这就是被偷的代码。
003C7444 00432ED9 返回到 1.00432ED9 补回代码后:
00403A3F 68 38F04000 push 1.0040F038////这才象入口嘛:)
00403A44 E8 5B9B0000 call 1.0040D5A4 ; jmp to comdlg32.GetOpenFileNameA
00403A49 85C0 test eax,eax
00403A4B 74 17 je short 1.00403A64
00403A4D 68 15F14000 push 1.0040F115
00403A52 E8 2C000000 call 1.00403A83
00403A57 8B0D 04F04000 mov ecx,dword ptr ds:[40F004]
00403A5D E3 05 jecxz short 1.00403A64
00403A5F E8 229B0000 call 1.0040D586 ; jmp to kernel32.GlobalFree
00403A64 E8 059B0000 call 1.0040D56E ; jmp to kernel32.ExitProcess
00403A69 55 push ebp 到入口后设置区段为完全权限,然后就可以用PETOOLS来DUMP了(因为用LORDPE不行!),删除FUCK区段及其数据,再用ImportREC v142+修复IAT。保存为DUMP_.EXE ,程序可以运行了! 第五步,修复区段: 加壳试试。晕!不能加壳。总是在这里出错:
004024C3 . F3:AA rep stos byte ptr es:[edi]////出错!
004024C5 > 61 popad
004024C6 . C9 leave
004024C7 . C3 retn ecx=00008B10 (十进制 35600.)
al=FF
es:[edi]=[00477000]=???////无477000内存地址! 00403918 . 8B75 28 mov esi,dword ptr ss:[ebp+28]
0040391B . 8B4D 2C mov ecx,dword ptr ss:[ebp+2C]
0040391E . 898D C4FEFFFF mov dword ptr ss:[ebp-13C],ecx
00403924 F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[esi]////出错!
00403926 . FF75 30 push dword ptr ss:[ebp+30]
00403929 . 8F85 C8FEFFFF pop dword ptr ss:[ebp-138]
0040392F . 33D2 xor edx,edx
00403931 > 42 inc edx
00403932 . FF75 58 push dword ptr ss:[ebp+58] ecx=00004E6F (十进制 20079.)
ds:[esi]=[004086F3]=C0
es:[edi]=[0045A000]=???////无45A000内存地址!
用OD载入脱壳后的程序,到入口后观察内存镜像: 内存映射
地址 大小 Owner 区段 包含 类型 访问 初始访问 映射为
00400000 00001000 Dumped_ 00400000 (itself) PE header Imag 01001002 R RWE
00401000 0000D000 Dumped_ 00400000 .text code Imag 01001002 R RWE
0040E000 00001000 Dumped_ 00400000 .rdata Imag 01001002 R RWE
0040F000 00001000 Dumped_ 00400000 .data Imag 01001002 R RWE
00410000 00002000 Dumped_ 00400000 .rsrc data,resources Imag 01001002 R RWE
00412000 00033000 Dumped_ 00400000 FUCK Imag 01001002 R RWE
00445000 00001000 Dumped_ 00400000 .mackt imports Imag 01001002 R RWE
00450000 00005000 00450000 (itself) Priv 00021004 RW RW 观察原程序到入口进的内存镜像: 内存映射
地址 大小 Owner 区段 包含 类型 访问 初始访问 映射为
内存映射
地址 大小 Owner 区段 包含 类型 访问 初始访问 映射为
00010000 00001000 00010000 (itself) Priv 00021004 RW RW
00020000 00001000 00020000 (itself) Priv 00021004 RW RW
003C3000 00001000 00030000 Priv 00021104 RW 防护 RW
003C4000 0000C000 00030000 stack of 主要线 Priv 00021104 RW 防护 RW
003D0000 00001000 003D0000 (itself) Map 00041002 R R
003E0000 00006000 003E0000 (itself) Priv 00021004 RW RW
003F0000 00001000 003F0000 (itself) Map 00041004 RW RW
00400000 00001000 1 00400000 (itself) PE header Imag 01001002 R RWE
00401000 0000D000 1 00400000 .text code Imag 01001002 R RWE
0040E000 00001000 1 00400000 .rdata Imag 01001002 R RWE
0040F000 00001000 1 00400000 .data Imag 01001002 R RWE
00410000 00002000 1 00400000 .rsrc data,resources Imag 01001002 R RWE
00412000 00033000 1 00400000 FUCK SFX,imports Imag 01001002 R RWE
00450000 00031000 00450000 (itself) Priv 00021004 RW RW
呵呵,看出问题来了吧!脱壳后的程序450000区段只有5000H大小,而原程序却有31000H大小!两者相差2C000H。
知道了原因就好办了。在DUMP_.EXE文件的最后增加一个大小为31000H的区段!然后用LordPE重建一下就可以了。不过重建只选PE验证选项噢!260K->272K附件:unpacked.rar
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)