深入解析PE檔案結構之匯出表獲取

2021-06-03 23:03:56 字數 3410 閱讀 9877

新學期新氣象,一般是小學作文的開頭,在此引用一下。

最近有時間坐下來仔細研究一下pe檔案結構了,以前遇到這種問題時總是拆東牆補西牆。學的不夠透徹。幾天來一番研究之後,和大家分享一下。

pe的檔案結構從dos頭開始,其主要作用就兩個乙個是若是在dos環境下輸出一句話。另乙個作用就是找到pe檔案頭的位置,這是我們要關心的,本文只注重所要關心的問題——匯出表。和一些你再眾多網上資料上很難找到的細節,至於整體的pe結構網上的資料中說的很詳細。

首先,pe檔案的載入原理這裡就不多說了,整個複雜的過程都是由pe裝載器完成的,過程不是一兩句話能夠說清楚的,這裡我們只需要注意乙個細節就可以了。pe裝載器將pe檔案已檔案對映的方式從磁碟對映到記憶體,在對映時pe檔案被載入到記憶體的開始位置叫做基址,我們用lpimagebase來表示。我們首先需要知道我們如何將乙個pe檔案載入到記憶體,並獲得基址。

handle hfile = createfile("c:\\example.exe", 

generic_read|generic_write,

file_share_read,

null,

open_existing,

file_attribute_normal,

null);

if(hfile==invalid_handle_value)

//記憶體對映檔案的基址

if (lpbaseaddress == null)

這裡我們需要關心的是乙個叫image_optional_header的結構,中文名稱叫「可選映象頭部」,說是可選的,其實非常重要。這個結構是在image_nt_herders結構中,並且是第二個成員變數。

typedef struct image_nt_herders

pimage_dos_header pdosheader=(pimage_dos_header)lpbaseaddress;

pimage_nt_headers pntheaders=(pimage_nt_headers)(lpbaseaddress + pdosheader->e_lfanew);

/可選映象頭部

typedef struct _image_optional_header

image_optional_header, *pimage_optional_header;

pntheaders->optionalheader;

然後我們需要注意image_data_directory這個陣列,這個陣列一般有15個元素,每個元素都記錄著這個pe檔案的重要資料結構。我們來看看這個陣列的每個元素的內容。

是不是很讓人吃驚?有了這個陣列,獲取一些pe資訊就非常簡單了,一般我們或者是計算機病毒所關心的多數是匯出表(eat),匯入表(iat),表,分別是這個陣列的第0個元素和第12個元素。這個方法和網上的一些eat iat位址獲取方法有所不同。很是方便。

而pntheader->optionalheader.datadirectory[0]又是乙個結構體,這個結構體的定義如下:

typedef struct _image_data_directory  image_data_directory, *pimage_data_directory;
pntheader->optionalheader.datadirectory[0].virtualaddress

到這裡我們已經找到了pe檔案的匯出表相對位址了(rva),現在的問題是,我們如何將匯出表中存放的匯出函式資訊給弄出來。

我們先看看匯出表是個什麼東西:

//匯入位址表

typedef struct _image_export_directory

image_export_directory,*pimage_export_directory;

不難看出addressofnames;就是存放匯出函式的乙個陣列rva了。但是這裡有乙個小問題。導致我在這個問題上花了半天時間。addressofnames;中存放的確實是乙個rva(相對位址),但是不是直接指向函式陣列的,而是指向了乙個存放位址的陣列也就是乙個dword陣列,這個陣列的每乙個元素存放乙個匯出函式的rva,這樣說來有點繞,我們已一張圖說明:

這就給我這種菜鳥造成了一定的麻煩,誒基礎語法還是很重要啊。。。

所以位址需要這樣獲取(這裡已經加上了基址lpimagebase,後面說明)

dword * k=(dword *)(pexport->addressofnames+lpbaseaddress);    //rvaêý×éê×µøö·

char * functionname=(char *)(*k+lpbaseaddress);

#include "windows.h"

#include "stdio.h"

void doshow(char * place)

//äú´æó³éäîä¼þµä»ùö·

if (lpbaseaddress == null)

pimage_dos_header pdosheader=(pimage_dos_header)lpbaseaddress;

pimage_nt_headers pntheaders=(pimage_nt_headers)(lpbaseaddress + pdosheader->e_lfanew);

pimage_export_directory pexport=(pimage_export_directory)(pntheaders->optionalheader.datadirectory[0].virtualaddress+lpbaseaddress);

int num=pexport->numberofnames;

printf("dllêç%s\n",pexport->name+lpbaseaddress);

printf("¹²óð%d¸öº¯êý\n",pexport->numberofnames);

printf("º¯êýðòºå º¯êýãû\n");

for (i;iaddressofnames+lpbaseaddress+4*i); //rvaêý×éê×µøö·

char * functionname=(char *)(*k+lpbaseaddress);

printf("%d %s\n",i+1,functionname);

} unmapviewoffile(lpbaseaddress);

closehandle(hfile);

}int main()

另外我還寫了介面,給大家展示一下吧。

下面的任務是嘗試更加困難的iat表的改寫,如插入dll,實現pe病毒的基本功能等等,如果可能,一定會給大家分享我的「成果」。

最後菜鳥言論,僅供娛樂。

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

上篇文章 pe檔案結構詳解 二 可執行檔案頭 的結尾出現了乙個大陣列,這個陣列中的每一項都是乙個特定的結構,通過函式獲取陣列中的項可以用rtlimagedirectoryentrytodata函式,datadirectory中的每一項都可以用這個函式獲取,函式原型如下 base 模組基位址。dire...

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

上篇文章 pe檔案結構詳解 二 可執行檔案頭 的結尾出現了乙個大陣列,這個陣列中的每一項都是乙個特定的結構,通過函式獲取陣列中的項可以用rtlimagedirectoryentrytodata函式,datadirectory中的每一項都可以用這個函式獲取,函式原型如下 base 模組基位址。dire...

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

上篇文章 pe檔案結構詳解 二 可執行檔案頭 的結尾出現了乙個大陣列,這個陣列中的每一項都是乙個特定的結構,通過函式獲取陣列中的項可以用rtlimagedirectoryentrytodata函式,datadirectory中的每一項都可以用這個函式獲取,函式原型如下 base 模組基位址。dire...