PE文件結構(三) 輸入表

PE文件結構(三)


參考

書:《加密與解密》

視頻:小甲魚 解密系列 視頻



輸入表


    輸入函數,表示被程序調用但是它的代碼不在程序代碼中的,而在dll中的函數。對於這些函數,磁盤上的可執行文件只是保留相關的函數信息,如函數名,dll文件名等。在程序運行前,程序是沒有保存這些函數在內存中的地址。當程序運行起來時,windows加載器會把相關的dll裝入內存,並且將輸入函數的指令與函數真在內存中正的地址聯繫起來。輸入表(導入表)就是用來保存這些函數的信息的。


    在   IMAGE_OPTIONAL_HEADER 中的 DataDirectory[16]  數組保存了 輸入表的RVA跟大小。通過RVA可以在OD中加載程序通過 ImageBase+RVA 找到 輸入表,或者通過RVA計算出文件偏移地址,查看磁盤中的可執行文件,通過文件偏移地址找到輸入表。

   

    輸入表是以一個IMAGE_IMPORT_DESCRIPTOR(IID)數組 開始的,每一個被PE文件隱式的鏈接進來的dll都有一個IID,IID數組的最後一個單元用NULL表示。


IMAGE_IMPORT_DESCRIPTOR 結構:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
	_ANONYMOUS_UNION union {              //00h
		DWORD Characteristics;
		DWORD OriginalFirstThunk; 
	} DUMMYUNIONNAME;
	DWORD TimeDateStamp;                  //04h
	DWORD ForwarderChain;                 //08h
	DWORD Name;                           //0Ch
	DWORD FirstThunk;                     //10h
} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;



    其中Name是dll名字的指針。OriginalFirstThunk指向一個IMAGE_THUNK_DATA數組叫做輸入名稱表Import Name Table(INT),用來保存函數,FirstThunk也指向IMAGE_THUNK_DATA數組叫做輸入地址表Import Address Table(IAT)。


IMAGE_THUNK_DATA 結構:

typedef struct _IMAGE_THUNK_DATA32 {
	union {
		DWORD ForwarderString;
		DWORD Function;
		DWORD Ordinal;
		DWORD AddressOfData;
	} u1;
} IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32;

    當IMAGE_THUNK_DATA 的值最高位爲1時,表示函數是以序號方式輸入,這時低31爲被當作函數序號。當最高位是0時,表示函數是以字符串類型的函數名方式輸入的,這時,IMAGE_THUNK_DATA 的值爲指向 IMAGE_IMPORT_BY_NAME 的結構的RVA。


typedef struct _IMAGE_IMPORT_BY_NAME {
	WORD Hint;
	BYTE Name[1];
} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;

Hint 表示這個函數在其所駐留dll的輸出表的序號,不是必須的。

Name 表示 函數名,是一個ASCII字符串以0結尾,大小不固定。



    INT保存的是這個程序導入這個dll中函數信息,它是固定的不會被修改。但是IAT會在程序加載時被重寫,當程序加載時,它會被PE加載器重寫成 這些函數的在內存中的真正地址。即把它原來指向的IMAGE_IMPORT_BY_NAME 改成 函數真正的地址。



那爲什麼要兩個 IMAGE_THUNK_DATA 數組?

   

    當程序加載時,IAT 會被PE加載器重寫,PE加載器先搜索INT,PE加載器迭代搜索INT數組中的每個指針,找出 INT所指向的IMAGE_IMPORT_BY_NAME結構中的函數在內存中的真正的地址,並把它替代原來IAT中的值。當完成後,INT就沒有用了,程序只需要IAT就可以正常運行了。


看下面圖,這個是可執行程序在磁盤中的時候:



這個是當程序被加載的是後:





實例分析:


    先找到輸入表RVA,通過IMAGE_OPTIONAL_HEADER 中的最後一個項  IMAGE_DATA_DIRECTORY 可以知道 輸入表相對與PE文件頭的偏移量爲80h可以找到輸入表達RVA。


圖片1


   

    但這個是RVA不是文件偏移地址。通過轉換可以知道,輸入表的文件偏移地址爲850h,



    查看850h,即IID,可以看到這個程序有兩個IID,即鏈接了 兩個dll,看到一個IID,可以知道它的OriginalFirstThunk 是 2098h  FirstThunk  爲200Ch,它們轉換後的文件偏移地址分別爲898h 和 80Ch


圖片2  IID數組





  查看OriginalFirstThunk跟FirstThunk ,可以發現這裏INT跟IAT的內容是一樣的,先看看第一個函數的信息,因爲第一位爲1,所以這裏00002122h 表示 IMAGE_IMPORT_BY_NAME 的RVA,轉化爲文件偏移值爲922h


圖片3  INT跟IAT



 


    查看922h 可以看函數名。


圖片4:







    我們可以從上面看到程序在磁盤中時 INT 與IAT內容一樣,都是指向 IMAGE_IMPORT_BY_NAME 。用OD加載程序,查看INT與IAT的內容


圖片5 INT



圖片6 IAT



    可以發現INT沒有發生變化,IAT變成了例如77D3C702h,IAT中的RVA被改成了函數的真正的地址。

   


    查看77D3C702h,就可以看到這個函數


圖片7





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章