PE文件格式學習(四):導入表


UPDATE:

  • 在文章的末尾更新了一張圖,在網上找的,有助於理解導入表的結構

1.概述

導入表是逆向和病毒分析中比較重要的一個表,在分析病毒時幾乎第一時間都要看一下程序的導入表的內容,判斷程序大概用了哪些功能。

導入表是數據目錄表中的第2個元素,排在導出表的后面。

2.導入表解析

先來了解一下導入表在PE文件中的結構體:

struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics; 
        DWORD   OriginalFirstThunk;         
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp; 
    DWORD   ForwarderChain;         
    DWORD   Name;
    DWORD   FirstThunk;              
} IMAGE_IMPORT_DESCRIPTOR;

在說明字段之前,需要說明的是,導入表是一個數組,每個元素都是上面的結構體,長度是14h,並且以14h字節的“0”作為數組結尾,如果程序導入了多個模塊,那么這個數組的長度應該是14h*(n+1)。

以下是字段的說明。

DWORD TimeDateStamp:一般為空,對應上圖的0x00000000

DWORD ForwarderChain:對應上圖的0x00000000

DWORD Name:導入模塊名的RVA,對應上圖的0x0000230c,

DWORD Characteristics:跟OrginalFirstThunk是聯合體,對應上圖的0x0000227c

DWORD OrginalFirstThunk:跟Characteristics是聯合體,一般情況下是OrginalFirstThunk生效,它是IMAGE_THUNK_DATA數組的RVA,對應上圖的0x0000227c

我們來看看IMAGE_THUNK_DATA結構體

struct _IMAGE_THUNK_DATA32{
    union {
        DWORD ForwarderString 
        DWORD Function ; 被輸入的函數的內存地址
        DWORD Ordinal ; 被輸入的API的序數值
       DWORD AddressOfData ; 高位為0則指向IMAGE_IMPORT_BY_NAME 結構體二
    }u1;
}IMAGE_THUNK_DATA32;

我們知道指向IMAGE_THUNK_DATA的RVA是0x0000227c,轉為offset是107ch,從107ch開始到0x00000000結束是一個完整的導入函數數組,如下圖:

我們對照圖來一一講解IMAGE_THUNK_DATA的字段。

ForwarderString:只有當IMAGE_IMPORT_DESCRIPTOR中的ForwarderChain有值時,它才有效

Function:導入函數的實際內存地址,只有在載入內存中時才有效

Ordinal:導入函數的導出序號,導出表中允許使用序號的方式導出函數,導入表也要有相應的機制。只有當IMAGE_THUNK_DATA的最高位是1的時候才有效

AddressOfData:當IMAGE_THUNK_DATA的最高位為0的時候有效,指向一個IMAGE_IMPORT_BY_NAME結構體數組,有沒有一種可能是最高位為1,並且是以函數名的方式導入函數的呢?我們知道最高位為1的最小數也是0x80000000,這個位置是系統空間,程序不可訪問,因此是不可能的。

IMAGE_IMPORT_BY_NAME結構體如下:

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

Hint:指出函數在所在的dll的輸出表中的序號

Name:指出要輸入的函數的函數名

接下來是IMAGE_IMPORT_DESCRIPTOR的最后一個字段。

DWORD FirstThunk:對應的是IMAGE_IMPORT_DESCRIPTOR那張圖中的0x00002000,在磁盤中它指向的位置跟OriginalFirstThunk是一樣的,同樣是指向IMAGE_THUNK_DATA數組。如果PE文件被加載進內存,FirstThunk指向的IMAGE_THUNK_DATA數組中的Function保存的就是真實內存中的函數地址,OriginalFirstThunk指向的同樣是IMAGE_THUNK_DATA數組,但是保存的並不是真實內存中的函數地址,而是IMAGE_IMPORT_BY_NAME數組的RVA,保存的是導入函數的文件名。

3.總結

1.重點需要分清在磁盤中和在內存中OriginalFirstThunk和FirstThunk的區別,在磁盤中二者都一樣,在內存中前者的IMAGE_THUNK_DATA結構生效的是AddressOfData字段,因此指向的是IMAGE_IMPORT_BY_NAME數組的RVA,所以它也被稱為INT,后者保存的是導入函數在內存中的真實地址,所以它被稱為IAT。

2.需要厘清一點概念就是,PE中導入表,也就是IMAGE_IMPORT_DESCRIPTOR結構在一個數組中,意味着一個PE文件中可能有多個導入表,每個導入表中只有一個OriginalFirstThunk和FirstThunk,但是他們指向的IMAGE_THUNK_DATA是一個數組,數組的元素個數代表函數的個數,如果是IMAGE_THUNK_DATA中的AddressOfData字段生效,它指向的是一個IMAGE_IMPORT_BY_NAME數組,這個數組中的元素個數跟IMAGE_THUNK_DATA中的可能不一樣,因為有的函數沒有名字。

3.凡是數組的最后一定是以0填充,長度是數組元素的大小,字符串以00作為結束。


免責聲明!

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



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