PE檔案格式詳細解析(二)--IAT

有毒發表於2020-03-08

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. 設計理念

  1. 不把函式庫包含進應用程式中,單獨組成DLL檔案,在需要使用時再進行呼叫。
  2. 使用記憶體對映技術將載入後的DLL程式碼、資源在多個程式中實現共享。
  3. 在對函式庫進行更新時,只更新DLL檔案即可。

3. 載入方式

DLL載入方式有兩種:顯式連結(Explicit Linking)隱式連結(Implicit Linking)

  • 顯示連結:程式在使用DLL時進行載入,使用完畢後釋放記憶體
  • 隱式連結:程式在開始時即一同載入DLL,程式終止時再釋放佔用的記憶體

    IAT提供的機制與DLL的隱式連結有關。

二、DLL呼叫的簡單理解

在OD中檢視程式的反彙編程式碼如下所示:

 

iat

 

在呼叫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結構:

 

iat1

2. PE裝載器把匯入函式輸入至IAT的順序

  1. 讀取IID的Name成員,獲取庫名稱字串(eg:kernel32.dll)

  2. 裝載相應庫:

    LoadLibrary("kernel32.dll")

  3. 讀取IID的OriginalFirstThunk成員,獲取INT地址

  4. 逐一讀取INT中陣列的值,獲取相應IMAGE_IMPORT_BY_NAME地址(RVA)

  5. 使用IMAGE_IMPORT_BY_NAME的Hint(ordinal)或Name項,獲取相應函式的起始地址:

    GetProcAddress("GetCurrentThreadld")

  6. 讀取IID的FirstThunk(IAT)成員,獲得IAT地址

  7. 將上面獲得的函式地址輸入相應IAT陣列值

  8. 重複以上步驟4~7,知道INT結束(遇到NULL)

四、總結

IAT是在學習PE檔案格式中重要的一部分,也是比較難的一部分,需要仔細學習,一定要熟練掌握。建議根據實際的PE檔案結合前面的分析步驟,親自動手多加分析,不斷熟悉分析流程。

相關文章