深入了解IAT原理


 

 

---------------------------編輯時突然死機自動保存也沒有用真的痛苦回頭補上------------------


輸入表中的這些間接跳轉是無法正常運行的,因為在正常情況,操作系統必須知道指向各個API函數名稱字符串的指針,然后通過GetProcAddress定位到各個API函數正確的入口地址並填充到IAT中,這樣這些間接跳轉才能起作用。可我們脫殼之后沒有這些指針了自然也就無法運行了。

搞明白了問題下一步就着手重建輸入表,下面我們來看看未加殼程序的IAT。

我們來定位該CrackMe PE結構中一些重要字段。首先在數據窗口中定位400000地址處。

 

單擊鼠標右鍵選擇-Special-PE header切換到PE頭的顯示模式。

 

 

往下拉。我們可以看到PE頭的偏移為100。即PE頭位於400100地址處。

 

繼續往下拉,我們可以看到IT(導入表)的指針,這里大家不要將其跟IAT搞混淆了。

IT = 導入表

IAT = 輸入函數地址表

我們知道當程序啟動之前操作系統會將各個API函數的地址填充到IAT中,那么IT(導入表)又是怎么一回事呢?首先我們定位到導入表,該導入表偏移值為3000(即虛擬地址為403000),長度為670(十六進制),

即403670為導入表的結尾。我們一起來看一看。

我們將數據窗口的顯示模式切換為正常狀態,這就是導入表了,我們來介紹一下導入表的結構吧。

我們選中的這20個字節是導入表的描述符結構。官方的叫法為IMAGE_IMPORT_DESCRIPTOR。每組為20個字節,IMAGE_IMPORT_DESCRIPTOR包含了一個的字符串指針,

該指針指向了某個的動態鏈接庫名稱字符串。

這里我們將IMAGE_IMPORT_DESCRIPTOR簡稱為IID。這里選中的部分為導入表中的第一個IID,共五個DWORD,其中5個DWORD字段的含義如下:

 

OriginalFirstThunk

TimeDateStamp       時間戳

ForwarderChain         鏈表的前一個結構

Name1             指向DLL名稱的指針

FirstThunk         指向的鏈表定義了針對Name1這個動態鏈接庫引入的所有導入函數

前三個字段不是很重要,對於我們Cracker來說,我們只對第4,5字段感興趣。

 

我們來看個例子:

正如大家所看到的,第4個字段為指向DLL名稱字符串的指針,我們來看看403290處是哪個DLL的名稱。

這里我們可以看到是USER32.DLL,第5個字段指向了USER32.DLL對應IAT項的起始地址,即403184。(不過我覺得位置不太對啊這也不是第四個DWORD啊而且403184在哪啊看不到啊)

既然我們已經知道了對應IAT的起始地址,那就跳到403184看看

這樣我們就到達了IAT,導入表的結束地址為403670(根據起始地址和長度計算得到)。導入表中的每個IID項指明了DLL的名稱以及其對應IAT項的起始地址。緊湊的排列在一起,供操作系統使用。

大量實驗表明,IAT並不一定位於在導入表中。IAT可以位於程序中任何具有寫權限的地方,只要當可執行程序運行起來時,操作系統可以定位到這些IID項,然后根據IAT中標明的API函數名稱獲取到函數地址即可。

下面我們來總結一下操作系統填充IAT的具體步驟:

1:定位導入表

2:解析第一個IID項,根據IID中的第4個字段定位DLL的名稱

3:根據IID項的第5個字段DLL對應的IAT項的起始地址

4:根據IAT中的指針定位到相應API函數名稱字符串

5:通過GetProcAddress獲取API函數的地址並填充到IAT中

6:當定位到的IAT項為零的時候表示該DLL的API函數地址獲取完畢了,接着繼續解析第二個IID,重復上面的步驟。

下面我們來手工的體驗一下這個步驟:

1)定位導入表

 

2)定位到導入表的起始地址

 

 

3)根據第一個IID項中的第四個字段得到DLL名稱字符串的指針,這里指向的是USER32.DLL

  

 

根據第五個字段的內容定位到IAT項的起始地址,這里是403184,我們定位到該地址處。

 

 

這里我們可以看到已經被填充了正確的API函數的入口地址,跟我們dump出來的結果一樣,我們再來看看相應的可執行文件偏移處的內容是什么。

 

這里我們可以看到第一個API函數的名稱位於4032CC地址處,我們定位到該地址處。

 

第一個API函數是KillTimer,我們在OD中看到的KillTimer的入口地址是操作系統調用GetProcAddress獲取到的。

 

這里我們可以看到KillTimer的入口地址為75EC79DB。該地址將被填充到IAT相應單元中去覆蓋原來的值,我們看到已經被覆蓋了。

 

這里是IAT中的第一元素。

我們再來看下一個元素,向后偏移4就是,是2f 7d ec 75這里,來看一看該API函數名稱字符串的指針是多少。

定位到可執行文件的相應偏移處:

 

32D8即4032D8,來看看該API函數的名稱是什么,這里由於該指針不為零,說明該API函數還是位於USER32.DLL中的。

 

這里我們可以看到第二個API函數是GetSystemMetrics,通過該函數名稱可以通過GetProcAddress獲取到其函數地址然后填充到IAT中。接下來按照以上步驟依次獲取USER32.DLL中的其他的函數地址,直到遇到的IAT項為零為止。我們來看一看可執行文件中結束項位於哪里。

我們可以看到當IAT中元素為零的時候表明USER32.DLL就搜索完畢了,我們接着來看下一個IID。

這里我們根據第4,5字段分別可以知道第二個DLL的名稱,以及對應IAT項的起始地址。

DLL的名稱字符串位於40329B地址處。

 

 

我們可以看到第二個DLL為KERNEL32.DLL,該DLL對應的IAT項起始地址為40321C。

這里我們可以看到前一個DWORD是零,表示USER32.DLL的API函數的結尾。40321C表示KERNEL32.DLL的API函數地址項的開始。

根據這些指針我們就可以定位到kernel32.dll中的各個API函數名稱字符串,進而獲取到其函數入口地址,接着填充到對應的IAT項中覆蓋原來的內容。

本章這里就結束了,我給大家描述了IAT被填充的整個過程,了解這個過程對大家來說是很有必要的,這部分內容是重建IAT必備的基礎知識,大家只有理解了其基本原理,然后配上適當的工具,就可以方便進行IAT的修復工作了。

好了,下一章我們將介紹具體如何修復IAT。

 

  僅允許非商業轉載,轉載請注明出處


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM