現在我們已經了解了IAT的的工作原理,現在我們來一起學習手動修復IAT,一方面是深入了解運行過程一方面是為了避免遇到有些阻礙自動修復IAT的殼時不知所措。
首先我們用ESP定律找到加了UPX殼后的OEP,現在我們處於OEP處,原程序區段已經解密完畢,我們現在可以進行dump了。
前面已經提到過,有很多dump的工具,OD有一個款插件OllyDump的dump效果也不錯,這里我們來使用另外一個工具PE TOOLS來進行dump。
PE TOOLS的界面是這樣的,我們用PE-TOOLS定位到CRACKME UPX所在的進程。單擊鼠標右鍵選擇-Dump Full。、


這里,我們就dump完畢了,接下來我們來修復IAT,關閉PE TOOLS,將dump后的dumped.exe保存到CRACKME UPX所在的目錄中。

我們知道沒有修復IAT,是不能運行的,我們雙擊Dumped.exe看看會發生什么。

提示無效的win32程序,我們需要修復IAT,我們需要用到一個工具,名字叫做Import REConstructor,不要關閉OD,將讓其斷在OEP處,Import REConstructor需要用到它。
運行Import REConstructor,定位到CRACKME UPX所在的進程。

這里很多初學者可能會有疑問-如何定位IAT的起始位置和結束位置呢?我們知道當前該CRACKME UPX進程停在了OEP處,此時殼已經將導入表破壞了,我們知道IID項的第四個字段為動態庫名稱字符串的指針,第五個字段為其對應IAT項第一個元素的地址,這些已經被殼破壞了,我們需要通過其他方式來定位。
我們知道API函數的調用通常是通過間接跳轉或者間接CALL來實現的。
即
JMP [XXXXXXX] or CALL [XXXXXX]
上一章我們已經介紹過了,這樣是直接調用IAT中保存的API函數地址。我們來看看CRACKME UPX。

這里我們看到第二行的CALL指令,OD提示調用的是Kernel32.dll中的GetModuleHandleA,是個間接跳轉,我們選中這一行,單擊鼠標右鍵選擇-Follow。


這里我們定位到獲取IAT中函數地址的跳轉表,這里就是該程序將要調用到的一些API函數,我們可以看到這些跳轉指令的都是以機器碼FF 25開頭的,有些教程里面說直接搜索二進制FF 25就可以快速的定位該跳表。
其實,並不是所有的程序都通過這種間接跳轉來調用API函數,所以直接搜索FF 25這種方法有時候會失敗,而通過定位某個API函數的調用處,然后Follow到跳表是這種方式才是一直有效的。
這里我們看到JMP [403238]:

403238是IAT的其中一個元素,里面保存的是GetModuleHandleA這個API函數的入口地址,我們dump出來的程序的IAT部分跟這里是一樣的,我們來看看IAT的起始位置和結束位置分別在哪兒。
其實,大家可以通過跳轉表中最小的地址和最大的地址算出IAT的起始位置和結束位置,但是比較慢,比較好的做法是,直接將數據窗口往上滾動,我們知道IAT的每個元素中都保存了一個API函數的入口地址,比如這里的76861245,在數據窗口中顯示的形式為45 12 86 76 (小端存儲),我們將顯示列數調整為兩列,這樣看起來更方便一些。

這里我們看到的就是整個IAT了,我們直接下拉到IAT的尾部,我們知道屬於同一個動態庫的API函數地址都是連續存放的,不同的動態庫函數地址列表是用零隔開的。
有一些殼會將這部分全部填零,使得我們的IAT重建工作變得異常困難,這里由於原程序還需要調用這些API函數,所以該殼沒有將這部分填零,我們現在來看看其中一個動態庫的IAT項,如下:

這里顯示了該DLL中的三個API函數,入口地址都是7C XXXXXX的形式,然后緊接着是一個零。
我們單擊工具欄中的M按鈕看看7C開頭的地址是屬於哪個DLL的。

我們可以看到這幾個地址處於kernel32.dll的代碼段范圍內。

當然在你們的機器上kernel32.dll可能在別的地址處,但在我的機器上,這幾個函數地址是屬於kernel32.dll的。

屬於kernel32.dll中的函數地址這里我用粉紅色標注出來了,我們再來看看77DXXXXX這類地址是屬於哪個DLL的。

這里我們可以看到77DXXXXX這類地址是屬於user32.dll的,我也用粉紅色標注出來了。

我們可以看到user32.dll的這些函數地址項上面是全零的,表示IAT的起始地址為403184,403184中存放的了IAT中的第一個元素。

這里我們用紅線標注出來了,403184是IAT的起始地址。有些強殼可能會將IAT前后都填充上垃圾數據,讓我們定位IAT的起始位置和結束位置更加困難。但是我們知道IAT中的數值都是屬於某個動態庫代碼段范圍內的,如果我們發現某數值不屬於任何一個動態庫的代碼段的話,就說明該數值是垃圾數據。
現在我們知道了IAT開始於403184,我們現在來看一看IAT的結束位置在哪里。
后面我們會遇到有些殼會將IAT重定向到殼的例程中去,然后再跳轉到API函數的入口處,這樣的話,上面這樣定位IAT的起始和結束位置的做法就行不通了。該如何應對這樣情況,我們后面再來介紹。

這里我們可以看到IAT的最后一個元素的地址形式為76XXXXXX,我們來看看它是屬於哪個DLL的。

這里我們可以看到其是屬於COMDLG32.DLL的,后面全是零了,所以40328C是IAT的結束位置。
好了,現在我們知道了IAT的起始位置和結束位置。
begin:403184
end:40328c




===========================================================================================================
Import REConstructor重建IAT需要三項指標:
1)IAT的起始地址,這里是403184,減去映像基址400000就得到了3184(RVA:相對虛擬地址)。
2)IAT的大小,IAT的大小 = 40328C - 403184 = 108(十六進制)
3)OEP = 401000(虛擬地址)- 映像基址400000 = 1000(OEP的RVA)。
僅允許非商業轉載,轉載請注明出處
