PE文件格式詳解(五)


0x00 前言

  前一篇了解了區塊虛擬地址和文件地址轉換的相關知識,這一篇該把我們所學拿出來用用了。這篇我們將了解更為重要的一個知識點——輸入表和輸出表的知識。

0x01 輸入表

  首先我們有疑問。這個輸入表是啥?為啥有輸入表?其實輸入表就是記錄PE輸入函數相關信息的一張表。那為什么要有這張表?答:原來PE文件運行過程中並不是獨立運行的,它必須要借助window系統的需對函數才能完成其功能。常見的如USER32KERNEL32DLL

輸入表所起的作用就是幫助載入的PE找到所需調用的函數。

  PE文件中,有個專門的數組,他們分別對每個被輸入的DLL程序。每個這樣的結構都給出了被輸入DLL的名稱並且指向一組函數指針,這組函數指針就是輸入地址表(Import Address Table 簡稱ITA)

  在之前講過的PE文件頭的IMAGE_OPTIONAL_HAEDER結構中的數據目錄表即DataDirectory[16]中第二個成員Imaport Table指向輸入表。輸入表是一個由IMAGE_IMPORT_DESCRIPORT(簡稱IID)的結構組成的數組。IID的結構如下:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {

 

DWORD    OriginalFirstThunk;

 

DWORD    TimeDateStamp;

 

DWORD     ForwarderChain;

 

DWORD     Name;

 

DWORD      FirstThunk;

 

} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;

下面介紹幾個重要字段:

OriginalFirstThunk:這個字段包含指向輸入名稱表(簡稱INT)的RVAINT是一個IMAGE_THUNK_DATA結構的數組,數組中的每個IMAGE_THUNK_DATA結構指向IMAGE_IMPORT_BY_NAME結構,數組最后以一個內容為0IMAGE_THUNK_DATA結構結束。

直接看這個描肯定感覺很繞,下面看看這幾個結構的關系圖,希望能夠幫助理解:

 其實就是1指向2再指向3

Name:輸入的DLL的名字指針,它是一個以00結尾的ASCII字符的RVA地址,該字符串包含輸入的DLL名。例如:KERNEL32.DLL,或者USER32.DLL

FirstThunk:包含指向輸入地址表(IAT)的RVAIAT也是指向IAMGE_THUNK_DATA結構。

這里的FristThunkOringinalFristThunk極為相似,作用也很類似,但是作用的先后有不同,后面將會做詳細講解。

下面來重點看看這個起着巨大作用的IMAGE_THUNK_DATA結構。

typedef struct _IMAGE_THUNK_DATA32 {
union {
PBYTE ForwarderString;
PDWORD Function;
DWORD Ordinal;
PIMAGE_IMPORT_BY_NAME AddressOfData;
} u1;
} IMAGE_THUNK_DATA32;

ForwarderString 指向一個轉向者字符串的RVA


Function 被輸入的函數的內存地址

 

Ordinal 被輸入的API的序數值


AddressOfData 指向IMAGE_IMPORT_BY_NAME

標識位黃色的這幾個字段都很重要,是的這個結構的字段全都很重要!

下面來看看AddressOfData字段指向的IMAGE_IMPORT_BY_NAME結構

  typedef struct _IMAGE_IMPORT_BY_NAME {

       WORD Hint;

       BYTE Name[1];

  } IMAGE_IMPORT_BY_NAME;

這個結構很簡單,只有兩個字段:

Hint字段:指示本函數在其所駐留的輸出表的中序號該域被PE裝載器用來在DLL的輸出表里快速查詢。該值不是必須的,一些鏈接器將此值設為0;

NAME字段:這個字段比較重要。它含有輸入函數的函數名,函數名是一個ASCII碼字符串,並以NULL結尾。注意,這里雖然將NAME的大小定義為字節,其實他是可變的。

   0x02 輸入地址表

   接下來要講的才是本文里最為關鍵的部分。通過上面的了解大概我們都會疑惑為啥這兩個數組都要指向IMAGR_IMPORT_BY_NAME結構?原因如下:

第一,第一個由OriginalFrist通過IMAGE_THUNK_DATA結構所指向的IMAGE_IMPORT_BY_NAME是單獨的一項,而且IMAGE_THUNK_DATA的值不可以更改,這個IMAGE_THUNK_DATA組成的數組就是INT,其實它是為FristThunk做為提示用的。

第二,第二個由FristThunk所指向的IMAGE_THUNK_DATA的值是由PE裝載器填寫的,他們的值構成了IAT。PE裝載器首先搜索OringinalFristThunk,通過它所指向的INT結構中的每個IMAGE_IMPORT_BY_NAME所指向的每個被載入函數的地址。然后通過加載器將值填充到FristThunk指向的IAT表中。

接下來對比一下加載前后的INT表和IAN表值變化:

 

                                                                                                                    加載前

 

                                                                                     加載后,顯示IAT的值已經填充了函數地址

我們最后要用到的即使PE加載后的ITA表。

  0x03 實例講解如何找到輸入表的FileOffset

  前面我們已經詳細講解了怎么找到數據目錄表,這里就不再綴述。我們直接找到數據目錄表的第二項,它的位置在180h處如下圖:

 

由此可知輸入表的RVA值為3000h,大小為52h

其實我們也可以可以直接在lordPE的區段表中找到FileOffset的值如下圖:

 

值為A00h

hexwrokshop直接跳轉到該位置(大小為52h)。如下圖:

 由於IMAGE_THUNK_DATA的五個字段都是雙字,因此按照八個字節依次讀出數組中第一個結構的每個字段:第一個OriginnalFristThunk為:0000 3028 第一個TimeDateStamp00000000。第一個ForwardChain為:00000000。第一個Name值為:00003038,第一個FristThunk值為:00003030

也可以用LordPE查看IMAGE_THUNK_DATA的字段值及名字如下圖:

 

可以知道調用了的是USE32.DLL

數組中的其余值也可以依次讀寫出來

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM