IAT的填充過程與執行流程

IAT的填充過程與執行流程

IAT是什麼?為什麼它在脫殼修復中扮演著如此重要的地位?它在內存中是怎麼樣排列的,又是怎樣獲取的呢?

調試器:OllyDbg

環境:WinXP SP3 虛擬機

(一)IAT

什麼是IAT呢。同一個函數,在A電腦裡的首地址和在B電腦裡的首地址是不一定相同的。系統版本不同,補丁版本不同,都會導致同一個函數的地址有所差異。

如果找不到正確的系統API地址程序就沒法正常調用函數,自然就沒法運行。為了提升系統的兼容性,每次執行程序時軟件都會重新獲取一次 基於當前的系統的API的地址,並把這些地址集中起來管理,組成一個表。我們把這個表叫輸入函數地址表,簡稱輸入表。即IAT(import address table)。

有些殼沒有徹底破壞掉IAT結構。比如ASpck,我們以一個加Aspack的課件為例,我們首先使用ESP定律來到OEP,此時殼已經將IAT還原完畢了。

(關於ESP定律的詳細解釋可以參考壇主大大的文章https://bbs.pediy.com/thread-20366.htm)

然後,來看一個調用函數的實例。

IAT的填充過程與執行流程

call ,點擊這一行按下回車,來到跳轉表

IAT的填充過程與執行流程

接著按下空格鍵,看到未經修飾的原始代碼為 jmp [403238]

IAT的填充過程與執行流程

jmp [403238] ,數據窗口跟隨403238,看到 [403238] = 752d582e,如下圖。

所以 jmp[403238] 等價於jmp 752d582e ,而 752d582e 是函數GetModuleHandle 的首地址,從而達到了調用 GetModuleHandle 函數的目的。

當然並不是所有程序都保留有跳轉表結構,本例對IAT的保存比較完整和系統,有跳轉表。

IAT的填充過程與執行流程

那麼能不能直接寫 jmp 752d582e呢?不能,因為這個地址在每臺電腦都不一樣。必須用[4031ac]間接調用77d507ea。

本節我們初步瞭解了IAT長什麼樣,下一節我們接下來我們來了解IAT的原始結構及獲取方法

(二)IAT的原始結構及獲取方法

根據上一節的預備知識可知,數據窗口跟隨 403238,取出裡面的內容,就是是GetModuleHandle函數的真實地址

IAT的填充過程與執行流程

選中 752d1245 ,右鍵,點擊“查看可執行文件”,如下圖所示,最左上角的那裡

IAT的填充過程與執行流程

原本的 403238 變成了1038, 752d1245變成了355E。 這是為什麼呢

我們把1038 叫文件偏移地址,這個地址加上402200就是403228。

355e是相對虛擬地址(RVA),它加上基址 400000(image base)得到一個虛擬內存地址40355e(VA),跟隨地址40355e發現裡面的內容是該函數的名稱字符串如下圖所示。

IAT的填充過程與執行流程

偏移地址的內容裡存儲著字符串,利用字符串, 接下來,程序調用GetProcAddress獲取到函數的真實地址,並將該地址填充到40355e所在的區域。注意這裡是存儲偏移地址的地方,而不是存儲字符串的地方。

IAT就由這樣的步驟重複執行而形成的。

我們使用十六進制工具winhex驗證一下。載入課件,定位1038,裡面也是0000355e,再來到40355e,裡面是字符串GetModuleHandle

所以程序需要用獲取哪些函數,該信息早就已經存在程序裡了,在程序運行前用GeProcAddress獲取這些函數的地址填充到IAT就能運行了。

字符串信息事先保存在程序中,但一旦IAT獲取完畢,字符串往往會被刪除。

(三)導入表與輸入表詳解

在數據窗口右擊-指定-PE頭,然後轉到400000(基址),查看PE文件,找到import table address=3000.這表示導入表指針偏移是3000,真實地址等於3000加上基址,即403000。

IAT的填充過程與執行流程

我們先來區分一下導入表(IT)和輸入表(IAT)。導入表是IT(import table),輸入表是IAT(import address table).IT的描述符結構是每5個Dword為一個單元,這個單元叫IID,如圖所示

IAT的填充過程與執行流程

一個IID有五個字段,每個字段佔一個Dword,但前三個字段一般沒用,有用的是第四字段和第五字段。第四字段加基址403290,這裡存放dll名稱。我們定位到403290看一下

IAT的填充過程與執行流程

如圖所示,dll的名稱是user32.dll

第五字段裡的內容加基址,作為指針指向的內容是這個dll的第一個函數地址。

IAT的填充過程與執行流程

導入表雖然包含了輸入表,但IAT不一定與IT所在的內存空間相鄰,它可以位於任何一個具有寫入權限的地方。即使他們分隔很遠也可以,換言之,在內存空間中可以不連續。IID通過第五個雙字裡的函數地址與IAT鏈接起來,這相當於一個鏈表。

總結,先在PE文件裡找到IT的位置,接著根據IT裡第一個IID的第四字段定位到dll的名稱,第五個字段定位dll對應的IAT項的起始位置。接著根據IAT裡的字符串偏移,提取出函數的名稱,接著利用GetProcAddress來獲取函數的地址。

最後將函數的地址填充進去。一直這樣重複,當獲取到的不再是字符串偏移地址而是00000000時,即表示當前dll裡所有函數的IAT填充完成了。來到IT的下一個IID裡重複剛才的過程。可以看到下一個dll是kernal32.dll,以此類推。

IAT的填充過程與執行流程

以上是填充IAT的完整過程。

認識了IAT,接下來我們就要著手修復了,以後如果還有時間,我會分享IAT修復的文章給大家。

原文鏈接:[原創]IAT的填充過程與執行流程-『加殼脫殼』-看雪安全論壇


分享到:


相關文章: