一、工具及殼介紹
使用工具:Ollydbg,PEID,ImportREC,LoadPE,IDA,Universal Import Fixer,OllySubScript
此篇是加密殼的第二篇,更詳細的步驟和思考,請查看第一篇:手工脫殼之 未知加密殼 【IAT加密+混淆+花指令】
PESpin殼:
二、脫殼之尋找OEP
1、硬件斷點失效
嘗試ESP定律,但硬件斷點未斷下。
(原因其實是殼做了反調試,后面部分介紹)
2、采用API斷點+單步跟蹤
API下斷:
殼導入了LoadLibrary 和 GetProAddress,可以從API下手。
按照經驗來說,跟蹤GDI32.dll的基地址。因為其它DLL,如kernel32.dll取出的函數,殼有可能用於自己的代碼而非修復IAT。
跟蹤GDI32的基地址。多觀察寄存器窗口和堆棧窗口。
DLL導出表:
DLL INT:
DLL IAT:
DLL 序號表:
通過RVA取得函數名:
跟蹤字符串,接下來可能有字符串循環。
函數名 首個字節跟0x53比。0x53 == ' S '。
而且每次的值都不一樣。可見是取對應字母開頭的函數名。
查看首個H開頭的函數名,下條件斷點。
字符串在減少,疑似於計算哈希值,
預判:根據上一篇加密殼的經驗,這樣的循環可能跟哈希加密,IAT加密有關。
預操作:記錄從DLL IAT取出函數地址的 指令地址 和 存放進exe IAT 指令的地址。
3、確定目標
確定循環的判斷臨界點,跳出循環,跟蹤最后的結果。
3.1、API Address
目標1:尋取出DLL IAT的函數地址。
字符串循環條件臨界點:
跳出循環,疑似哈希值。
交換寄存器。
的確是進行哈希值比較。
在條件成立的下一條指令下斷點。
跟蹤哈希值,得到取函數地址的指令地址。
取DLL IAT函數地址的指令地址 :
記錄下一條指令地址:0x438F9F
3.2、Put EXE IAT
目標2:尋 把DLL IAT函數地址 存放進 exe IAT 的指令地址。
此處還不知道exe IAT的位置,所以只能跟蹤函數地址EAX了。
多觀察帶方括號 MOV [xxx], xxx 之類的指令。
代碼中做了大量的混淆和花指令,如下,純粹無意義的指令,干擾分析。
(混淆和花指令具體見后面部分)
記錄PESpin殼特征:
記錄殼的一些操作:
取API函數前部分字節,並判斷。
對取出的字節 做一些操作。
最終拷貝進指定地址,數據窗口跟隨反匯編看出點端倪。
推測殼是在 IAT引用 與 真正API調用 之間增加代碼屏障,還是帶混淆的屏障。
這樣做順便可以對IAT進行加密,阻止ImportREC解析。
3.3、IAT加密
流程:偷取函數前部分字節,申請空間,制造混淆代碼塊。
CALL(IAT引用) ->> 內存代碼(混淆) -->> API
以下跟蹤證明推測正確:
再逐步取出字節。
構造混淆,IAT引用CALL進來就是這個樣子。
觀察內存空間首地址0x200000。推測可能准備填入exe IAT。
因為混淆和花指令,很多仔細分析都會做無用功,不知哪條真那條假。所以要確定目標,定點分析。
存進IAT指令:
存進exe IAT 指令的地址:
記錄下一條指令地址:0x43918C
3.4、IAT重定向
現在,存在IAT的位置的是 申請出來的內存地址,內存的地址 –>> API的地址。
查看數據窗口,仔細一看你會發現,IAT被重定向了。
API的地址用0隔開,這明顯不是IAT結構,是殼自己建立的IAT,ImportREC無法解析。
3.5、IAT重定向解決方案:
- 用OD腳本修復內存地址為真正API地址
- 用Universal Import Fixer重建IAT
- 接着用ImportREC重建導入表。
3.6、OEP
接下來就是跳出修復IAT的循環,找到OEP了。
多注意 比較指令 和 遠跳。
找OEP的過程,感覺就是在"花"海里遨游~~.....
跨區段遠跳,一般是跳到OEP。
OEP:
記錄OEP地址:0x409486
3.7、記錄分支
查看調用模塊:
IAT引用,有些加密,有些未加密。
可見在殼修復IAT時,有些函數地址並沒有做相關加密處理,直接放回去了。
這就意味着在存進exe IAT 的循環中,多了一條分支,這像是有意擾亂分析者的腳步。
找一塊地址密集的地方,在首部,下硬件斷點,跟蹤分析出分支位置。
此處存進exe IAT的指令地址跟上一處的不同,地址正好可以做為分支的條件判斷。
記錄分支指令:
跳過call下一條指令地址: 0x439101
四、快速定位OEP
特征碼搜索:
在殼解密TEXT段后,可以按各個版本的編譯器的OEP特征碼,進行逐個搜索。
如:
VC++的OEP特征碼:
55 8B EC 6A FF
如果做了OEP特征偷取,可以針對某一條OEP相關指令,對內存進行暴力搜索。
五、 SEH異常鏈反調試
殼操作:利用SEH異常鏈清理硬件斷點,進行反調試。
很多情況下,要么就硬件斷點斷不下,要么就斷下的位置不正確。
懷疑硬件斷點被清除了。
按經驗,首先推測在異常處理里進行反調試。
OD取消忽略異常。
Shift+F9 忽略異常運行,總共觸發9處異常,列出首幾處。
第三處和第四處斷在了同一個地方,但異常處理函數不同。
方案:通過在后方異常點 設置硬件斷點,來判斷前方異常點的異常處理 是否做了反調試。
逐個排查,確定是第3個異常點,清理了硬件斷點。
查看異常處理函數,可以在反調試函數前下硬件執行斷點。
這里為了進行更好的分析,在此處Dump下來,采用IDA分析。
的確是對Dr1、2、3、4清理為零了,並且對Dr6、7進行了操作。
反反調試:編寫OD腳本時,下硬件斷點在此函數,並去掉反調試指令。
記錄地址:0x43AF59,NOP掉字節0x1A。
六、OD腳本及修復
//清除所有硬件斷點 BPHWC //清除所有軟件斷點 BC //清除所有內存斷點 BPMC //IAT地址 VAR IATAddress //OEP斷點 BPHWS 409486,"x" //取IAT指令 BPHWS 438F9F,"x" //存IAT指令 BPHWS 43918C,"x" //硬件反調試代碼 BPHWS 43AF59,"x" _LOOP: RUN //去掉硬件反調試代碼 cmp eip,43AF59 JNZ _Sign1 fill 43AF59,1A,90 //清除反調試硬件斷點 BPHWC 43AF59 _Sign1: //取IAT判斷 CMP eip,438F9F JNZ _Sign2 MOV IATAddress,eax _Sign2: //分支判斷 CMP eip,439101 JNZ _Sign3 //不作操作 BPHWS 43AF59,"x" _Sign3: //存IAT的地方 CMP eip,43918C JNZ _Sign4 MOV [edi],IATAddress _Sign4: //OEP CMP eip,409486 JNZ _LOOP MSG "到達OEP"
OD腳本修復加密:
使用Universal Import Fixer 重定向修復IAT表:
從上面的殼代碼的運行地址可以看出,殼的代碼是運行在最后一個區段的,可以推斷最后一個區段是殼的區段。
當Dump下來的時候,最后一個區段就沒用了,所以可以重定向到此區段。
再用ODDump,ImportREC新建導入表:
七、脫殼成功
八、混淆花指令
分析經驗:
混淆:無意義的垃圾指令,干擾分析,干擾反匯編引擎,使指令產生多種解釋。
花指令:無意義的大量跳轉,干擾分析。
花指令塊:無意義跳轉。
跳轉指令被截斷。
混淆讓反匯編出錯。
下硬件讀寫斷點,會難確定上一條是什么指令。
混淆使同樣意思的指令被肢解成多條。
一個混淆和花指令結合的循環,就是上面的字符串處理循環。
通過STC設置進位標志 和 CMC進位標志求補 控制跳轉,花指令。
個人總結:
附件:
KID