補 PE結構遍歷輸入表 因為不愛,所以都錯

2021-10-05 05:34:10 字數 3326 閱讀 3376

#include

#include

dword rva_raw

(dword rva,

unsigned

char

* base)

}return raw;

}int

main()

//獲取檔案的大小

dword filesize =

getfilesize

(hfile,

null);

lpdword sizetoread =0;

//申請一塊和檔案大小相同的新記憶體

unsigned

char

* pbuf =

newunsigned

char

[filesize]

;//將這塊記憶體用0填充

zeromemory

(pbuf, filesize)

;//填充之後,將檔案讀取到這段記憶體空間裡邊,這個時候檔案將儲存在磁碟上的狀態,也就是需要進行位址轉換

int i =

readfile

(hfile, pbuf, filesize, sizetoread,

null);

if(i ==0)

//定位dos頭;

pimage_dos_header dosheader =

(pimage_dos_header)pbuf;

//定位nt頭;

pimage_nt_headers nt_header =

(pimage_nt_headers)

(pbuf + dosheader-

>e_lfanew)

;//定位optionheader

pimage_optional_header32 optionheader =

&(nt_header-

>optionalheader)

;//定位資料目錄表

pimage_data_directory datadir =

(pimage_data_directory)

(optionheader-

>datadirectory)

;//定位輸入表的rva

dword importrva =

(dword)datadir[1]

.virtualaddress;

//進行位址轉換,獲取輸入表在磁碟檔案中的偏移

dword importraw =

rva_raw

(importrva,pbuf)

;//定位輸入表的資料結構

pimage_import_descriptor importtable =

(pimage_import_descriptor)

(importraw + pbuf)

;//判斷輸入表是不是為空,因為輸入表以全零作為結束標誌

while

(importtable-

>firstthunk)

//如果最高位是0,表示這個函式是以名字匯出的

else

int++

; iat++;}

importtable++;}

}

接下來說一些需要注意的點:

1 也是最重要的一點:不管在這次的遍歷匯入表還是上次的遍歷遍歷匯出表,**部分其實都有乙個安全隱患.這個點就是.容易造成記憶體洩露,因為再讀取檔案的時候,我使用new來申請了一塊新的記憶體空間,但是再遍歷完畢之後並沒有去釋放這塊記憶體空間,這個算是比較危險的地方了,釋放的話,直接用delete去釋放就好了.

2:遍歷匯入表的過程其實相對比遍歷匯出表較為簡潔.下圖記錄了匯入表的結構圖:

每乙個int的結構都對應乙個image_thunk_data,當然實際上,int和iat指向的都是image_thunk_data結構,而且還有重要的一點就是,需要注意匯入的方式,再判斷匯入的方式之後,需要注意,當目標函式是以序號匯入的時候,正常輸出就好.但是當目標函式是以名稱匯入的時候,需要注意這個時候的int所對應的image_thunk_data->address指向image_import_by_name結構體,也就是上圖的hint name 所對應的結構,這個時候image_import_by_name->name才是我們的目標匯入函式的名稱.

3:至於目標函式是以什麼方式匯入的,可以使用image_snap_by_ordinal32這個巨集來進行判斷,這個巨集的定義如下:(64位和32位都包含在內)

#define image_ordinal_flag64 0x8000000000000000

#define image_ordinal_flag32 0x80000000

#define image_ordinal64(ordinal) (ordinal & 0xffff)

#define image_ordinal32(ordinal) (ordinal & 0xffff)

#define image_snap_by_ordinal64(ordinal) ((ordinal & image_ordinal_flag64) != 0)

#define image_snap_by_ordinal32(ordinal) ((ordinal & image_ordinal_flag32) != 0)

4:對於pe載入器來說,int和iat意味著什麼?

首先,獲取到image_import_description結構中name欄位的資料(也就是獲取目標模組的名字)

第二步執行loadlibrary(「目標模組的名稱」,將目標模組載入到記憶體中)

第三步:獲取到int的位址

第四步:逐一迴圈獲取int陣列的值(前邊已經說過,每乙個int項都指向乙個image_thunk_data的資料結構),如果是以序號匯出的,獲取相應函式的序號和位址,如果是以名稱匯出的,先指向相應的image_import_by_name結構,之後獲取該結構裡的name欄位和hint的資料.

第五步:根據上邊獲取到的name欄位的資料,使用getprocaddress()函式來獲取到函式的位址

第六步:獲取到iat的位址

第七步:將上邊獲取到的函式的位址填充到獲取到的iat的位址,迴圈進行.直到遇到全零的image_import_description結構.

從上邊的過程,我們不難發現,在實際的使用過程中,iat的資料可能跟int的資料是相同的,治理之所以使用可能,是因為,還存在一些特殊情況.

其實從名字來理解也更容易理解,iat裡邊儲存著目標函式的位址,int裡邊儲存著目標函式的名字.

關於PE檔案 輸入表

什麼是輸入表?輸入表就相當於exe檔案與 dll檔案溝通的橋梁,形象的可以比喻成兩個城市之間交流的高速公路。在pe檔案對映到記憶體後,windows將相應的dll檔案裝入,exe檔案通過 輸入表 找到相應的dll中的匯入函式,從而完成程式的正常執行。輸入表的組成與工作原理?首先大概了解整體的結構 三...

PE結構 匯出表

那麼,作業系統是如何來獲取函式位址呢,也就是getprocaddress的實現,這裡就涉及到了匯出表。匯出表,會記錄這個庫函式的位址是多少,所以簡單來說getprocaddress就是查匯出表來獲取位址,如何查就是下面的話題了。匯出意味著需要提供api給他人使用,一般來說會是一些dll之類的,所以,...

PE檔案中的輸入表

pe檔案中的輸入表含有三個重要結構iid,int,iat。pe檔案為需要載入的dll檔案建立乙個iid結構,乙個dll與乙個iid對應。int是輸入名稱表,iat輸入位址表,在沒有繫結輸入的情況下磁碟中的檔案int與iat相同。如果有繫結輸入的話因為繫結輸入的函式其磁碟檔案中的iat項就已經是對應函...