轉載:http://www.52pojie.cn/thread-467703-1-1.html
工作需要要脫一個VMP殼,我是一個從來沒接觸過脫殼的人。瞬間那種心情遇到的人應該都知道!沒辦法硬着頭皮找教程,7天看完了 《天草的殼的世界》嘗試脫殼下面是我的脫殼過程希望大牛多多指正!
1、准備工具,FEID(查殼工具)、DIE(查殼工具)、LordPE(dump工具)、ImpRec(IAT修復工具)、UIF(IAT修復工具)、CFF(文件優化工具)、OD(吾愛破解專版 調試工具)
2、查殼 PEID
區段顯示是vmp1,看來是VMP殼編寫語言還是不能確定上DIE
顯示編程語言是VC++的,VMP殼
3、開OD准備脫殼、OD設置如下
打開進程到入口看下
4、跑OEP
啥也卡不懂,不過沒關系知道是VMP殼就好辦,直接CTRL+G 輸入 VirtualProtect 下斷 如下圖(如果提示未知,先在內存窗口找到 kernel32.dll代碼段 進去后在轉到就到了)
F9跑起來,這是會段下
注意NewProtect 這項 等於 PAGE_READONLY 是停下,否則一直F9 按慢點別跑飛了
到0401000處看看,代碼是否已經解碼
已經解碼, 搜索特征碼 EB0B85F375078BC6C1E0100BF0
這是OEP第一個CALL的尾部,根據他找到OEP
OEP 就是 00a6f7c8,不過這才是第一步 這時候DUMP 是沒用的 因為VMP加密了IAT 我們需要還原他
5、還原IAT
隨便找一個IAT調用函數跟一下,剛好OEP下面就有兩個 FF25 型的IAT 調用,跟進去看下
還是啥都看不懂,不過沒關系 既然是調用IAT函數,肯定會在某一時刻調到真實函數地址去的 繼續跟下面把整個跟的流程貼上來
這是整個流程的實際執行的代碼 ,現在分析下
01059D91 53 push ebx 保護環境
01059D92 66:0FB6DB movzx bx,bl 垃圾代碼
01059D96 66:BB 5D55 mov bx,0x555D 垃圾代碼
01059D9A BB 5AC27200 mov ebx,0072C25A 這才是最終對EBX操作所以上面兩條都是沒用的代碼
00F3BBFF 8B9B 25697400 mov ebx,dword ptr ds:[ebx+0x746925] 計算地址
01196B98 8D9B 5071F632 lea ebx,dword ptr ds:[ebx+0x32F67150] 計算地址
00EA9FC2 871C24 xchg dword ptr ss:[esp],ebx 和棧頂交換,並還原EBX的原始值
00F9FC9D C2 0400 retn 0x4 還原EBX 並返回函數
這時候看下堆棧 棧頂出現真實函數的地址
<ignore_js_op>
00F9FC9D C2 0400 retn 0x4 分析下這條指令的執行流程,先EIP=棧頂的值 也就是真實函數地址,棧頂+4+4 懂匯編的人就會發現,棧頂+8的位置保存是當前CALL的返回地址 那執行了這條指令后返回地址不是沒有了么?因為這個IAT調用 沒加密前是 FF25型的 也就是 jmp [????????] 所以不需要返回地址 ,而調用這個IAT的時候 是有一個CALL的進CALL的時候就會PUSH返回地址到堆棧,所以這個IAT處理的很巧妙!執行完真實函數后直接就返回到調用IATCALL的下面繼續執行了。
看圖片發現 這個CALL 下面有一條 RETN指令 看來這條 是VMP加上去的了,但是不要忽略了這條指令 因為這條指令很重要,VMP在獲取 IAT地址的最后RETN的地址 會隨機JMP到代碼他添加的RETN 上,並不完全是在殼段 所以這個RETN 要留到最后處理。
再找一個FF25 型的IAT調用看看
跟進去看下,下面是執行流程代碼
00FB7DC7 90 nop
00FB7DC8 0FB7D6 movzx edx,si 垃圾代碼
00FB7DCB 66:0FBED1 movsx dx,cl 垃圾代碼
00FB7DCF 5A pop edx 出棧
00FB7DD0 871424 xchg dword ptr ss:[esp],edx 交換棧頂的值,還原 EDX原始值
00FB7DD3 52 push edx 保護環境
00FB7DD4 66:0FBED1 movsx dx,cl 垃圾
00FB7DD8 0FB7D6 movzx edx,si 垃圾
00FB7DDB BA B7757D00 mov edx,007D75B7 計算地址
010DFDAD 8B92 3D036900 mov edx,dword ptr ds:[edx+0x69033D] 計算地址
0102B837 8D92 B52FE512 lea edx,dword ptr ds:[edx+0x12E52FB5] 計算地址
00EACB30 871424 xchg dword ptr ss:[esp],edx 函數真實地址給棧頂 並還原環境
0115D36E C2 0400 retn 0x4
這個FF25 CALL 的第四行 有個POP edx 而進這個CALL之前 有一個push edx ,可以看出 這個push edx 也是垃圾代碼是 VMP自己添加上去的,看來VMP 會隨機在上下 填充一個字節,在上面就是 PUSH 一個寄存器,在下面就是 retn
找一個 FF15型的CALL看看
跟進去看下流程
010B27B9 BE B34E6E0B mov esi,0xB6E4EB3 垃圾代碼
00EFFC5B 5E pop esi 出棧
00EEB9B0 873424 xchg dword ptr ss:[esp],esi 交換棧頂的值,還原 ESI原始值
00F437BB 56 push esi 保存環境
00F8D827 BE 4B084800 mov esi,0048084B 計算地址
00FA55B3 8BB6 C005B900 mov esi,dword ptr ds:[esi+0xB905C0] 計算地址
010E8053 8DB6 3F68AD31 lea esi,dword ptr ds:[esi+0x31AD683F] 計算地址
00F44191 873424 xchg dword ptr ss:[esp],esi 真實函數地址給棧頂,還原環境
0057A761 C3 retn
第二行 pop esi 看來這個CALL 的push esi 是垃圾指令了,但是 發現這個 是retn 為什么不是,retn 04 呢?因為這個是 FF15 型調用,也就是 call [????????] 需要執行完后返回到call 下面繼續執行
再找一個FF15型調用看看
跟進去看下流程
00E77D14 90 nop
00E77D15 51 push ecx 保存環境
00E77D16 66:F7D1 not cx 垃圾代碼
00E77D19 8B4C24 04 mov ecx,dword ptr ss:[esp+0x4] 棧頂+4(調用CALL的返回地址)給ECX,
00FB7CFF 8D49 01 lea ecx,dword ptr ds:[ecx+0x1] 取 返回地址+1的值 給ECX
01013FB5 894C24 04 mov dword ptr ss:[esp+0x4],ecx 重新寫入到返回處
01013FB9 B9 A1598A00 mov ecx,008A59A1 計算地址
010566B2 8B89 94C36C00 mov ecx,dword ptr ds:[ecx+0x6CC394] 計算地址
00E95200 8D89 19378077 lea ecx,dword ptr ds:[ecx+0x77803719] 計算地址
00FEA363 870C24 xchg dword ptr ss:[esp],ecx 真實函數地址給棧頂,還原環境
010ABADE C3 retn
這個 有點不一樣啊,很簡單 看調用CALL 的下面有一個 RETN啊,這要是正常返回 程序還不得跑飛啊,VMP巧妙的利用 4 5 6三行代碼 就搞定了,這寫殼的人真是腦洞大開啊!
所有的IAT加密就這樣完了嗎??? NO 還有更腦洞大開的 往下看
跟進去看看
0119D768 90 nop
0106B2C9 872C24 xchg dword ptr ss:[esp],ebp 交換棧頂的值,還原棧頂
00F3E26F 55 push ebp 保存返回地址
00F3E270 F7D5 not ebp 垃圾代碼
00F3E272 50 push eax 保存環境
00F3E273 B8 D41D4300 mov eax,00431DD4 計算地址
00F3E278 66:8BEB mov bp,bx 垃圾代碼
00F3E27B 8B80 41F7BE00 mov eax,dword ptr ds:[eax+0xBEF741] 計算地址
00F3E281 66:0F4FE8 cmovg bp,ax 垃圾代碼
00F3E285 66:8BE8 mov bp,ax 垃圾代碼
00F3E288 8D80 903F170C lea eax,dword ptr ds:[eax+0xC173F90] 計算地址
00F3E28E 0FB7E8 movzx ebp,ax 垃圾代碼
00F3E291 8BE8 mov ebp,eax 真實函數地址給 EBP
00F3E293 58 pop eax 還原 寄存器
011B5D71 C3 retn
這是在干啥呢?? 咋把真實函數地址 給了 EBP呢? 看調用處的下面 有一個 call ebp 明白了吧 這是把 mov xx,[????????] 整成了一個CALL哦,再來看下堆棧 調用處pop EBP , CALL內 第2行 有把棧頂的值還原了,然后把函數的返回地址重新PUSH進去,這里處理的很巧妙,所有 調用處的 pop ebp也是垃圾指令,這就完了???NO還有往下看
跟進去看下
00E97E5D 90 nop
00E97E5E 0FBFDB movsx ebx,bx 垃圾代碼
010C1083 50 push eax 保存環境
010C1084 8B4424 04 mov eax,dword ptr ss:[esp+0x4] 獲取當前CALL的返回地址給EAX
00E2EB3F 8D40 01 lea eax,dword ptr ds:[eax+0x1] 獲取當前CALL返回地址+1給EAX
00E2EB42 0F45DB cmovne ebx,ebx 垃圾代碼
00E2EB45 66:0FB6DB movzx bx,bl 垃圾代碼
00E2EB49 894424 04 mov dword ptr ss:[esp+0x4],eax 保存返回地址
00E2EB4D B8 012C4300 mov eax,00432C01 計算地址
00E2EB52 66:0FBEDB movsx bx,bl 垃圾代碼
00E2EB56 66:8BDF mov bx,di 垃圾代碼
01170378 8B80 F58CC000 mov eax,dword ptr ds:[eax+0xC08CF5] 計算地址
0117037E 0FB7DC movzx ebx,sp 垃圾代碼
01170381 0F41DE cmovno ebx,esi 垃圾代碼
01170384 F6D7 not bh 垃圾代碼
01170386 8D80 145A2C32 lea eax,dword ptr ds:[eax+0x322C5A14] 計算地址
0117038C B3 85 mov bl,0x85 垃圾代碼
0117038E 8ADE mov bl,dh 垃圾代碼
01170390 8BD8 mov ebx,eax 真實函數地址給 EBX
01170392 0FBFC2 movsx eax,dx 垃圾代碼
01170395 C6C4 E2 mov ah,0xE2 垃圾代碼
01170398 0FC8 bswap eax 垃圾代碼
0117039A 58 pop eax 還原環境
0117039B C3 retn
認真看 了上面的部分,這里不難理解了吧, 4 5 8行處理調用處的 下面 retn 的,函數是獲取 EBX的調用值的
一共6種 IAT相關的處理,所以我是 一邊寫腳本一邊罵寫 VMP殼的人,要不要這么坑啊,我要的脫的程序特別大 跑一遍要 1個小時,我也不記得我跑了多少遍了!哎!說來都是淚,新手就是這樣啊!不多說了下面貼上腳本!需要的自己去下!
6、用UIf 修復IAT
7、用lodepe dump
8、用imprec 修復IAT
9、用cff 去掉殼段
至此VMP脫殼完成!