1 檢視殼程式資訊
- 使用ExeInfoPe
![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本
分析:
發現這個殼的類型沒有被識别出來,Vc 6.0倒是識别出來了,Vc 6.0的特征是 入口函數先調用GetVersion()
2 用OD找OEP
- 拖進OD
發現 這個殼和我們的正常程式很像。但是并不是我們的真正程式入口![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本
- 因為vc6.0特征的第一個調用的是GetVersion(),給GetVersion()下 硬體斷點
//第一次斷下來,但是根據棧回溯,調用者并不是我們的子產品//第二次斷下來,就應該是了![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本 //找到入口後 棧上右鍵 反彙編視窗跟随![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本 //如下![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本 ![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本
- 在OD看記憶體布局,一般.rdata的最前面是放的IAT,而且OD資料視窗預設就是.rdata的起始位置。
- 也可以點一個call /jmp [];看一下來找IAT表
![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本
- 對那個地方下一個硬體寫入斷點 --DWORD,即目前面的殼程式在修改的時候就能段下來找到殼的加密算法的地方
3 對加密部分分析
這個分析的過程,需要自己去啃,是分享不了的。
我是從GetProcAddress 開始分析的,過程中往前觀察分析了幾次來解答這裡的一些寄存器的内容資訊、局部變量的資訊,以下是我主要分析的部分:
- 通過對IAT表位置下硬體寫入斷點,我們找到了這個修改IAT的地方
![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本
斷下這個GetProcAddress()這個函數 調用之後EAX儲存的是 目前要填入IAT的真實位址
004385B9 FF15 CC924300 CALL DWORD PTR DS:[0x4392CC] ; kernel32.GetProcAddress
//開始懷疑修改進IAT的函數内容--加密代碼前面幾句--寫死的寫死opcode 到底意欲何為:![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本
在記憶體視窗跳到[EBX-0X30]選擇反彙編觀察一下:![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本
- 發現 這就是解密IAT代碼。
總結:用寫死 opcode (用于解密IAT)的首位址替代IAT中的函數位址,然後每次IAT調用的時候都會去調用這個代碼塊使用。![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本
4 分析了加密算法了流程後
- 這時候我們隻需要儲存正确的函數位址值到IAT,那麼這個程式就能脫掉了。
![]()
脫殼系列_2_IAT加密殼_詳細版_解法1_包含腳本
然後和前面幾篇一樣的流程dump到本地,用impREC修複一下IAT
運作沒毛病!!
附:還可以使用OD腳本修正IAT
思路:腳本如下:
- 調用getprocAddress之後,立刻使用一個臨時變量儲存起來,
- 再待殼修改IAT後,立刻修改回正确的函數位址(前面儲存的臨時變量)
//1.定義變量 MOV dwGetApiAddr,004385bf MOV dwWriteAddr,004385f0 MOV dwOEP,00409486 //2.初始化環境 BC //清除軟體斷點 BPHWC //清除硬體斷點 BPMC //清除記憶體斷點 //下硬體執行斷點 BPHWS dwGetApiAddr,"x" BPHWS dwWriteAddr,"x" BPHWS dwOEP,"x" //3.建構邏輯 /* -- 用一個臨時變量來存儲 真正的函數位址 -- 在加密邏輯代碼執行完,并且寫入IAT後,立刻改回 */ LOOP0: RUN //相當于od -- F9 CMP dwGetApiAddr,eip//如果是執行完GetProcAddress後 JNZ CASE1 mov dwTemp,eax JMP LOOP0 CASE1: CMP dwWriteAddr,eip MOV [edi],dwTemp JMP LOOP0 CASE2: CMP dwOEP,eip JNZ LOOP0 MSG "改回來了哈哈"