PE檔案結構詳解(三)PE匯出表

2021-09-06 17:53:51 字數 3400 閱讀 8908

上篇文章 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中,有幾項的名字都和匯入...