PE文件和COFF文件格式分析——導入表

因爲之前已經介紹了PE基本格式以及導出表相關,因此一些基本的東西就直接省略,用工具直接定位。

PE文件和COFF文件格式分析(1)

PE文件和COFF文件格式分析——導出表

本次以 kernel32.dll 爲例,查看其導入表。

首先用 Stud_PE.exe 查看導入表的位置如下:
在這裏插入圖片描述
也就是在文件的地址 0x084c88。跳過去看看,以紅線開始
在這裏插入圖片描述
查看導入表定義:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    } 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)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

可見大小是 0x14 個字節。上面看到Stud_pe 中展示了導入表大小是 0x744。0x744 / 0x14 = 0x5D。
因爲這裏是一個數組!一共有 0x5D 個結構。用 0x84C88 + 0x744 = 0x853cc
在這裏插入圖片描述
看最後的 0x14 個字節是全0。也就是這個是數組結束的標誌。即實際有效的是 0x5C 個導入表。
用 PE view 查看一下:
在這裏插入圖片描述
右側是根據每個DLL 分開的。可以數一數確實是那麼多。
因爲是數組,這裏就分析一個就可以,看圖:
在這裏插入圖片描述
上面說到一個 IMAGE_IMPORT_DESCRIPTOR 的大小是 0x14 個字節,是上圖中紅色劃線之間的部分。
對應每一個值就是:
在這裏插入圖片描述
有關上面幾個字段的含義可以參考:
PE文件學習筆記(一)—導入導出表
PE文件格式學習(四):導入表

這裏簡單說一下,中間2個爲0 的字段暫時不管,以後理解了再補充。
Name 就是這個導入表的名稱的地址,這裏是 0xa18d4,計算成文件地址是 0x868d4。
在這裏插入圖片描述
可以看到是一個以 0 結尾的字符串。
佐證一下:
在這裏插入圖片描述
另外兩個重要的字段的含義:

/*
	FirstThunk;
	OriginalFirstThunk;
	這兩個值含義在文件中應該是一樣的,指向一個結構體數組 IMAGE_THUNK_DATA32[N]
	但是當PE 加載進內存就有差異了,FirstThunk 指向的數組和OriginalFirstThunk指向的不再一樣
	FirstThunk 指向的數組的含義是函數地址!!),而 OriginalFirstThunk 指向的是名稱和序數地址,也就是 IMAGE_IMPORT_BY_NAME 的地址
	該數組結束的標誌是以一個 IMAGE_THUNK_DATA32 全部爲0 作爲標誌
	IMAGE_THUNK_DATA32 最高位如果爲0,則IMAGE_THUNK_DATA32.AddressOfData是一個RVA,指向一個IMAGE_IMPORT_BY_NAME結構,用來保存名字信息
	反之如果最高位爲1,則低16位是導出序數。
	*/

因此,簡單的說,在文件裏面,通常 OriginalFirstThunk 指向一個數組的首地址,這個數組是:
IMAGE_THUNK_DATA32[N]。
至於 32 和 64 位差距暫時沒研究。
看一下:
在這裏插入圖片描述
發現 FirstThunk = 0x816d0 ->RA = 0x666D0
OriginalFirstThunk = 0xa0fcc ->RA = 0x85fcc

在這裏插入圖片描述
在這裏插入圖片描述
我們發現,雖然 FirstThunk OriginalFirstThunk 的值不一樣,但是對應地址寫的 IMAGE_THUNK_DATA32[N]
的地址是一樣的,印證了上面的說法。
由於這個地址最高位是0,一次他說一個指向一個名字結構的地址,這個名字結構就是 typedef struct

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

也就是前兩個字節是導入函數在對應 DLL 中的序數,後面是一個以 0 結尾的字符串。

這個地址 0x0a1898(轉換成文件地址:0x86898)。。跳過去:
在這裏插入圖片描述
可以看到序數是 0x0001,函數名字是 RtlCaptureStackBackTrace。
同理,看圖
在這裏插入圖片描述
由於紅線是 IMAGE_THUNK_DATA32[N] 數組首地址,以全0結構體結束,可以看到一共有三個值,第四個就是全0。
不妨再看第二個元素是 0x0a18B4,轉換成文件地址:0x868B4:
在這裏插入圖片描述
可以看到,其實就是接着上面的一個名字結構體的。該DLL 有三個導入函數:
看工具分析結果:
在這裏插入圖片描述
上面說到:

發現  FirstThunk = 0x816d0 	->RA = 0x666D0 
OriginalFirstThunk = 0xa0fcc 	->RA = 0x85fcc

對比就可以發現:工具第一列就是 IMAGE_THUNK_DATA32 數組的每個元素的地址(文件中的地址)
這每個元素指向另一個地址(名稱結構 IMAGE_IMPORT_BY_NAME 的地址),也就是 第二列 DATA 的值(這個值是RVA)。
Value 列,就是 IMAGE_IMPORT_BY_NAME 中序數和名字了。

最後,再看:
在這裏插入圖片描述

在這裏插入圖片描述

可以發現
FirstThunk = 0x816d0 ->RA = 0x666D0
OriginalFirstThunk = 0xa0fcc ->RA = 0x85fcc
兩個字段指向的是不同的兩個數組 IMAGE_THUNK_DATA32 [N] 的地址,數組以一個全0的結構體結束。
雖然這兩個數組不同,但是數組的內容是一模一樣的。
工具看一下:
在這裏插入圖片描述
在這裏插入圖片描述
可以發現兩個不同的地方,對應的實際數據是一樣的。

參考下圖,來源: PE文件格式學習(四):導入表
在這裏插入圖片描述
按照一些說法,上圖中 IAT,再加載進內存中後就不是和INT 一樣相同指向了。(未證實)

最後附上代碼分析的結果(一共 0x5C 個導入表)~:
在這裏插入圖片描述

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