PE格式詳細講解8 輸入表

2021-06-29 02:04:12 字數 3357 閱讀 6355

在此之前,我們已經對這個輸入表進行了一些實踐和理解,這有助於大家對這個概念更進一步的加深認識。

小甲魚覺得,越是複雜的問題我們應該越是去動手操作它,認識它,這樣才容易熟悉它!

在上一節課我們像小鹿一樣的亂撞,終於撞到了輸入表裡邊包含的函式名稱,嘿嘿,不過位址,我們還是沒能找著……

這節課我們將深入來剖析輸入表的結構,通過結合例項分析來幫助大家理解輸入表的工作原理。

回顧一下,在 pe檔案頭的 image_optional_header 結構中的 datadirectory(資料目錄表) 的第二個成員就是指向輸入表的。

而輸入表是以乙個 image_import_descriptor(簡稱iid) 的陣列開始。

每個被 pe檔案鏈結進來的 dll檔案都分別對應乙個 iid陣列結構。

在這個 iid陣列中,並沒有指出有多少個項(就是沒有明確指明有多少個鏈結檔案),但它最後是以乙個全為null(0) 的 iid 作為結束的標誌。

image_import_descriptor 結構定義如下:

image_import_descriptor struct 

union

characteristics dword ?

originalfirstthunk dword ?

ends

timedatestamp dword ?

forwarderchain dword ?

name dword ?

firstthunk dword ?

image_import_descriptor ends

它指向first thunk,image_thunk_data,該 thunk 擁有 hint 和 function name 的位址。

在最近,它被設定為0xffffffff以表示繫結發生。

一般情況下我們也可以忽略該欄位。在老版的繫結中,它引用api的第乙個forwarder chain(傳遞器鍊錶)。

它可被設定為0xffffffff以代表沒有forwarder。

它表示dll 名稱的相對虛位址(譯註:相對乙個用null作為結束符的ascii字串的乙個rva,該字串是該匯入dll檔案的名稱。

如:kernel32.dll)。

它包含由image_thunk_data定義的 first thunk陣列的虛位址,通過loader用函式虛位址初始化thunk。

在orignal first thunk缺席下,它指向first thunk:hints和the function names的thunks。

這個originalfirstthunk 和 firstthunk明顯是親家,兩傢伙首先名字就差不多哈。那他們有什麼不可告人的秘密呢?

來,我們看下面一張圖(畫的很辛苦,大家仔細看哈):

firstthunk

我們看到:originalfirstthunk 和 firstthunk 他們都是兩個型別為image_thunk_data 的陣列,它是乙個指標大小的聯合(union)型別。

每乙個image_thunk_data 結構定義乙個匯入函式資訊(即指向結構為image_import_by_name 的傢伙,這傢伙稍後再議)。

然後陣列最後以乙個內容為0 的 image_thunk_data 結構作為結束標誌。

我們得到 image_thunk_data 結構的定義如下:

image_thunk_data struc

union u1

forwarderstring dword ? ; 指向乙個轉向者字串的rva

function dword ? ; 被輸入的函式的記憶體位址

ordinal dword ? ; 被輸入的api 的序數值

addressofdata dword ? ; 指向 image_import_by_name

ends

image_thunk_data ends

我們可以看出由於是union結構,所以image_thunk_data 事實上是乙個雙字大小。

該結構在不同時候賦予不同的意義(偉大神奇不得鳥……)。

其實union這種資料結構很容易理解:說白了就是當時窮,能省就省,再說白了,就是幾兄弟姐妹輪流穿一條褲子去相親!

理解了吧?哈哈~

那我們怎麼來區分何時是何意義呢?

規定如下:

當 image_thunk_data 值的最高位為 1時,表示函式以序號方式輸入,這時候低 31位被看作乙個函式序號。

好,那接著我們討論下指向的這個 image_import_by_name 結構。

image_import_by_name 結構僅僅只有乙個字型資料的大小,存有乙個輸入函式的相關資訊結構。

其結構如下:

image_import_by_name struct

hint word ?

name byte ?

image_import_by_name ends

結構中的 hint 欄位也表示函式的序號,不過這個欄位是可選的,有些編譯器總是將它設定為 0。

name 字段定義了匯入函式的名稱字串,這是乙個以 0 為結尾的字串。

整個過程看起來有點繞有點煩,別急,後邊我們有演示哈。

為什麼由兩個並行的指標陣列同時指向 image_import_by_name 結構呢?第乙個陣列(由 originalfirstthunk 所指向)是單獨的一項,而且不能被改寫,我們前邊稱為 int。

第二個陣列(由 firstthunk 所指向)事實上是由 pe 裝載器重寫的。

好了,那麼 pe 裝載器的核心操作時如何的呢?這裡就給大家揭秘啦~

pe 裝載器首先搜尋 originalfirstthunk ,找到之後引導程式迭代搜尋陣列中的每個指標,找到每個 image_import_by_name 結構所指向的輸入函式的位址,然後載入器用函式真正入口位址來替代由 firstthunk 陣列中的乙個入口,因此我們稱為輸入位址表(iat)。

所以,當我們的 pe 檔案裝載記憶體後準備執行時,剛剛的圖就會轉化為下圖:

輸入位址表(iat)

此時,輸入表中其他部分就不重要了,程式依靠 iat 提供的函式位址就可正常執行。

工具:peinfo.exe, ultraedit, lordpe

解剖物件:hello.exe

PE格式詳細講解9 匯出表

有一些函式很多程式都會用到,為每乙個程式寫乙個相同的函式看起來似乎有點浪費空間。因此windows就整出了動態鏈結庫的概念,將一些常用的函式封裝成動態鏈結庫,等到需要的時候通過直接載入動態鏈結庫。將需要的函式整合到自身中,這樣就大大的節約了記憶體中資源的存放。如圖 pe格式詳細講解 有乙個重要的概念...

PE格式詳解講解1

下面的內容主要是圍繞這個圖來進行 這個頭部是為了相容早期的dos系統,pe檔案的第乙個位元組起始於乙個傳統的ms dos頭,被稱為image dos header,這個結構體完整的定義如下 注 最左邊是檔案頭的偏移量。image dos header struct image dos header ...

PE格式之千里追蹤輸入表

高數考完了,終於可以輕鬆的寫 了。哈哈 終於開始寫輸入表了。輸入表是我們專案的重頭戲。首先還是先介紹下輸入表的基本知識。自己寫的話有點麻煩,還是copy一下小甲魚辛辛苦苦打出來的課件吧 pe檔案頭的 image optional header 結構中的 datadirectory 資料目錄表 的第二...