#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項就已經是對應函...