IAT表

0X0

0 DLL介紹c++

DLL翻譯器爲動態連接庫,原來不存在DLL的概念只有,庫的概念,編譯器會把從庫中獲取的二進制代碼插入到應用程序中。在如今windows操做系統使用了數量龐大的庫函數(進程,內存,窗口,消息)採用這種包含庫的方式,會形成內存嚴重的浪費。所以,windows OS 設計者根據須要引入了DLL這一律念windows

(1) 不要把庫包含到程序中,單獨組成DLL文件,須要時調用便可
(2) 內存映射技術使加載後的DLL代碼,資源在多個進程中實現共享
(3) 更新庫時只要替換相關的DLL文件便可數組

0X01 IMAGE_IMPORT_DESCRIPTOR

IMAGE_IMPORT_DESCRIPTOR 結構體記錄着PE文件要導入哪些庫文件
IMAGE_IMPORT_DESCRIPTOR 結構體以下函數

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound INT (PIMAGE_THUNK_DATA) 存着INT表地址
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  // 0 if not bound,
                                            // -1 if bound, and real date\time stamp
                                            // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                            // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;                 // -1 if no forwarders
    DWORD   Name;                           //導入庫的名字
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses) 存着IAT表地址
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

執行一個普通程序每每須要導入多個庫,導入多個庫就存在多少IMAGE_IMPORT_DESCRIPTOR結構體,這些結構體造成了數組,且結構體數組最後以NULL結構體結束。測試

項目 含義
OriginalFirstThunk INT的地址(RVA)
Name 庫的名字
FirstThunk IAT的地址(RVA)

IAT 和 INT 存着不少IMAGE_THUNK_DATA,IMAGE_THUNK_DATA結構體彙總只有一個聯合體,通常用四字節的AddressOfData來獲取this

typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        //RVA 指向_IMAGE_IMPORT_BY_NAME 
    } u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;       //可能爲0,編譯器決定,若是不爲0,是函數在導出表中的索引
    BYTE    Name[1];    //函數名稱,以0結尾,因爲不知道到底多長,因此乾脆只給出第一個字符,找到0結束
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

INT 導入姓名錶 IAT爲導入地址表,程序在初始化時須要把獲取庫中的函數地址存入IAT表中進行IAT的初始化,在開始時INT和IAT指的是同一個結構體IMAGE_IMPORT_BY_NAME(我在XP環境中測試的時候記事本程序時在文件中,INT表存的是IMAGE_IMPORT_BY_NAME 結構體,IAT表存的是寫死的函數地址)操作系統

描述IMAGE_IMPORT_DESCRIPTOR 的示意圖
翻譯

下面瞭解一下PE裝載器把導入函數輸入至IAT的順序設計

  1. 讀取IID的Name成員,獲取庫名稱字符串("kernel32.dll")
  1. 裝載相應庫 ->LoadLibrary("kernel32.dll")
  2. 讀取IID的OriginalFirstThunk成員,獲取INT地址
  3. 逐一讀取INT中數組的值,該值是IMAGE_IMPORT_BY_NAME的地址,而後獲取IMAGE_IMPORT_BY_NAME結構體中的Hint 或者Name項 使用GetProcAddress()獲取相應的起始地址
  4. 讀取IID的FirstThunk(IAT)成員,獲取IAT地址
  5. 將上面獲取的函數地址輸入相應的IAT數組值
  6. 重複4-6這幾個步驟直到INT結束

0X02 在xp系統下用notepad.exe進行演示

0x021 從PE可選頭查找導出表的位置

IMAGE_IMPORT_DESCROPTOR 結構的起始地址存在於 可選頭的DataDirectory 數組第二個位置IMAGE_OPTIONAL_HEADER32.DataDirectory[1].VirtualAddress的值code

  1. 首先經過PEwiew查看 notepad.exe的PE可選頭 看出 IMPORT表 RVA 7604 => RAW 6A04
  1. 咱們查到了導入表的首地址咱們用HXd查看一下

咱們能夠看到數組的最後是以NULL結尾的

  1. 我先列一下第一個導入表對應的各個地址,全是F的話就是還未裝載,在進入內存是將會裝載
地址(RVA) 含義 地址(RAW)
7990 OriginalFirstThunk 6D90‬
FFFFFFFF TimeDateStamp 0
FFFFFFFF ForwarderChain 0
7AAC Name 6EAC‬
12C4 FirstThunk 06C4
  1. 先看一下這個庫的名字 是 comdlg32.dll
  1. 查看導入姓名錶 中的 IMAGE_THUNK_DATA32 結構

RVA 7A7A => RAW 6E7A 爲 IMAGE_IMPORT_BY_NAME 結構體的首地址

  1. 查看IMAGE_IMPORT_BY_NAME 結構體

能夠看出000F爲函數的編號 ,後面則是導入的函數名字 PageSetupDlgW

  1. 查看IAT表中的 IMAGE_THUNK_DATA32 結構

    IAT表中的IMAGE_THUNK_DATA32 結構存的就不是姓名錶的地址了,而是一個寫死了的,該函數的內存地址,爲了兼容其餘系統,程序在執行時會經過IAT和庫的導出表來動態獲取該函數的地址。並把地址存入IAT表的對應位置,而後進行下一個函數名稱查找,直到把全部函數查找完。
  1. 咱們經過OllyIce查看在內存中IAT表的樣子

看着該函數地址與在hxd文件同樣,那是由於在xp系統下,換個系統這兩個值就可能會不一致。

相關文章
相關標籤/搜索