上篇文章 pe檔案結構詳解(二)可執行檔案頭 的結尾出現了乙個大陣列,這個陣列中的每一項都是乙個特定的結構,
通過函式獲取陣列中的項可以用rtlimagedirectoryentrytodata函式,
datadirectory中的每一項都可以用這個函式獲取,函式原型如下:
base:模組基位址。
directory:資料目錄項的索引。
[cpp]
view plain
copy
#define image_directory_entry_export 0 // export directory
#define image_directory_entry_import 1 // import directory
#define image_directory_entry_resource 2 // resource directory
#define image_directory_entry_exception 3 // exception directory
#define image_directory_entry_security 4 // security directory
#define image_directory_entry_basereloc 5 // base relocation table
#define image_directory_entry_debug 6 // debug directory
#define image_directory_entry_architecture 7 // architecture specific data
#define image_directory_entry_globalptr 8 // rva of gp
#define image_directory_entry_tls 9 // tls directory
#define image_directory_entry_load_config 10 // load configuration directory
#define image_directory_entry_bound_import 11 // bound import directory in headers
#define image_directory_entry_iat 12 // import address table
#define image_directory_entry_delay_import 13 // delay load import descriptors
#define image_directory_entry_com_descriptor 14 // com runtime descriptor
size:對應資料目錄項的大小,比如directory為0,則表示匯出表的大小。
返回值表示資料目錄項的起始位址。
這次來看看第一項:匯出表。
匯出表是用來描述模組中的匯出函式的結構,如果乙個模組匯出了函式,那麼這個函式會被記錄在匯出表中,這樣通過getprocaddress函式就能動態獲取到函式的位址。函式匯出的方式有兩種,一種是按名字匯出,一種是按序號匯出。這兩種匯出方式在匯出表中的描述方式也不相同。模組的匯出函式可以通過dependency walker
工具來檢視:
上圖中紅框位置顯示的就是模組的匯出函式,有時候顯示的匯出函式名字中有一些符號,像 ??0cp2pdownloaduiinte***ce@@qae@abv0@@z,這種是匯出了c++的函式名,編譯器將名字進行了修飾。
下面看一下匯出表的定義吧:
[cpp]
view plain
copy
typedef
struct
_image_export_directory image_export_directory, *pimage_export_directory;
結構還算比較簡單,具體每一項的含義如下:
characteristics:現在沒有用到,一般為0。
timedatestamp:匯出表生成的時間戳,由聯結器生成。
majorversion,minorversion:看名字是版本,實際貌似沒有用,都是0。
name:模組的名字。
base:序號的基數,按序號匯出函式的序號值從base開始遞增。
numberoffunctions:所有匯出函式的數量。
numberofnames:按名字匯出函式的數量。
addressoffunctions:乙個rva,指向乙個dword陣列,陣列中的每一項是乙個匯出函式的rva,順序與匯出序號相同。
addressofnames:乙個rva,依然指向乙個dword陣列,陣列中的每一項仍然是乙個rva,指向乙個表示函式名字。
addressofnameordinals:乙個rva,還是指向乙個word陣列,陣列中的每一項與addressofnames中的每一項對應,表示該名字的函式在addressoffunctions中的序號。
第一次接觸這個結構的童鞋被後面的5項搞暈了吧,理解這個結構比結構本身看上去要複雜一些,
文字描述不管怎麼說都顯得晦澀,所謂一圖勝千言,無圖無真相,直接上圖:
在上圖中,addressofnames指向乙個陣列,陣列裡儲存著一組rva,每個rva指向乙個字串,這個字串即匯出的函式名,與這個函式名對應的是addressofnameordinals中的對應項。獲取匯出函式位址時,先在addressofnames中找到對應的名字,比如func2,他在addressofnames中是第二項,然後從addressofnameordinals中取出第二項的值,這裡是2,表示函式入口儲存在addressoffunctions這個陣列中下標為2的項裡,即第三項,取出其中的值,加上模組基位址便是匯出函式的位址。
如果函式是以序號匯出的,那麼查詢的時候直接用序號減去base,得到的值就是函式在
addressoffunctions中的下標。
用**實現如下:
[cpp]
view plain
copy
dword
* ceat::searcheat(
const
char
* szname)
} else
return
&pprocs[pordinals[i]];
} }
} return
null;
}
PE檔案結構詳解(三)PE匯出表
上篇文章 pe檔案結構詳解 二 可執行檔案頭 的結尾出現了乙個大陣列,這個陣列中的每一項都是乙個特定的結構,通過函式獲取陣列中的項可以用rtlimagedirectoryentrytodata函式,datadirectory中的每一項都可以用這個函式獲取,函式原型如下 base 模組基位址。dire...
PE檔案結構詳解(三)PE匯出表
上篇文章 pe檔案結構詳解 二 可執行檔案頭 的結尾出現了乙個大陣列,這個陣列中的每一項都是乙個特定的結構,通過函式獲取陣列中的項可以用rtlimagedirectoryentrytodata函式,datadirectory中的每一項都可以用這個函式獲取,函式原型如下 base 模組基位址。dire...
PE檔案結構詳解(四)PE匯入表
pe檔案結構詳解 二 可執行檔案頭的最後展示了乙個陣列,pe檔案結構詳解 三 pe匯出表中解釋了其中第一項的格式,本篇文章來揭示這個陣列中的第二項 image directory entry import,即匯入表。也許大家注意到過,在image data directory中,有幾項的名字都和匯入...