PE檔案格式詳細解析(二)--IAT
IAT,匯入地址表(Import Address Table),儲存了與windows作業系統核心程式、記憶體、DLL結構等相關的資訊。只要了理解了IAT,就掌握了Windows作業系統的根基。IAT是一種表格,用來記錄程式正在使用哪些庫中的哪些函式。
一、DLL
DLL,動態連結庫(Dynamic Linked Library)
1. 來源
在16位的DOS環境中,不存在DLL的概念,例如在C中使用printf函式時,編譯器會先從C庫中讀取相應函式的二進位制程式碼,然後插入到應用程式中。但是Windows支援多工,採用這種包含庫的方式會沒有效率,因為如果每個程式在執行時都將Windows庫中的函式載入進來,將造成嚴重的記憶體浪費,因此引入了DLL的概念。
2. 設計理念
- 不把函式庫包含進應用程式中,單獨組成DLL檔案,在需要使用時再進行呼叫。
- 使用記憶體對映技術將載入後的DLL程式碼、資源在多個程式中實現共享。
- 在對函式庫進行更新時,只更新DLL檔案即可。
3. 載入方式
DLL載入方式有兩種:顯式連結(Explicit Linking) 和 隱式連結(Implicit Linking)
二、DLL呼叫的簡單理解
在OD中檢視程式的反彙編程式碼如下所示:
在呼叫ThunRTMain()函式時,並非是直接呼叫函式,而是通過獲取0x00405164地址處的值-0x7400A1B0,該值是載入到待分析應用程式程式記憶體中的ThunRTMain()函式的地址。
需要注意的是,此處之所以編譯器不直接進行jmp 7400A1B0主要是因為以下兩點:
- DLL版本不同,由於作業系統的版本存在差異,DLL檔案版本也會存在差異
- DLL重定位,DLL檔案的ImageBase一般為0x10000000,如果應用程式同時有兩個DLL檔案需要載入--a.dll和b.dll,在執行時a.dll首先載入進記憶體,佔到了0x10000000,此時b.dll如果再載入到0x10000000,就會發生衝突,所以需要載入到其他的空白記憶體空間處。
三、IMAGE_IMPORT_DESCRIPTOR結構體
1. 結構介紹
該結構體中記錄著PE檔案要匯入哪些庫檔案,因為在執行一個程式時需要匯入多個庫,所以匯入了多少庫,就會存在多少IMAGE_IMPORT_DESCRIPTOR結構體,這些結構體組成陣列,陣列最後以NULL結構體結束。部分重要成員如下所示:
成員 |
含義 |
OriginalThunk |
INT的地址(RVA),4位元組長整型陣列,NULL結束 |
Name |
庫名稱字串的地址(RVA) |
FirstThunk |
IAT的地址(RVA),4位元組長整型陣列,NULL結束 |
下圖描述了notepad.exe之kernel32.dll的IMAGE_IMPORT_DESCRIPTOR結構:
2. PE裝載器把匯入函式輸入至IAT的順序
讀取IID的Name成員,獲取庫名稱字串(eg:kernel32.dll)
裝載相應庫:
LoadLibrary("kernel32.dll")
讀取IID的OriginalFirstThunk成員,獲取INT地址
逐一讀取INT中陣列的值,獲取相應IMAGE_IMPORT_BY_NAME地址(RVA)
使用IMAGE_IMPORT_BY_NAME的Hint(ordinal)或Name項,獲取相應函式的起始地址:
GetProcAddress("GetCurrentThreadld")
讀取IID的FirstThunk(IAT)成員,獲得IAT地址
將上面獲得的函式地址輸入相應IAT陣列值
重複以上步驟4~7,知道INT結束(遇到NULL)
四、總結
IAT是在學習PE檔案格式中重要的一部分,也是比較難的一部分,需要仔細學習,一定要熟練掌握。建議根據實際的PE檔案結合前面的分析步驟,親自動手多加分析,不斷熟悉分析流程。