PE檔案格式學習(三) 匯出表 Export

2021-09-30 16:54:55 字數 2923 閱讀 9444

上篇文章中介紹過,可選頭中的資料目錄表是乙個大小為0x10的陣列,匯出表就是這個陣列中的第乙個元素。

我們再回顧下資料目錄表的結構體:

struct _image_data_directory

image_data_directory, *pimage_data_directory;

imagebase:裝載基址,pe檔案在記憶體中的基位址,一般exe檔案的imagebase是0x400000

va:資料在記憶體中的位址,即虛擬位址。va = imagebase+rva(相對虛擬位址)

rva:相對虛擬位址,故名思義,它是相對於映象基址(imagebase)的虛擬位址, 假如imagebase是0x400000,rva是0x1000,那麼va就是0x401000

offset:資料在檔案中的偏移

資料目錄表中儲存的是rva,如果我們要在硬碟中分析檔案格式,需要將rva轉換成offset,為什麼要將rva轉為offset呢?直接用不是更方便嗎?

其實轉換的原因涉及到乙個區段對齊的概念,接下來我會進行詳細的講解,先說結論:程式在記憶體中的區段對齊值和在磁碟中的區段對齊值是不一樣的,所以區段資料在記憶體和在磁碟中的偏移一定是不一樣的,換句話說就是要進行轉換才能夠找到資料位址。

程式在被載入到記憶體中時,每個區段都會被「拉長」到0x1000的倍數,因為在32位系統中乙個記憶體分頁的大小是4kb,也就是0x1000,程式需要遵循系統的分頁機制。(分頁機制以後會寫一篇詳細的文章進行講解)

程式在磁碟中時,區段的大小都是0x200的倍數,也就是512,這是因為硬碟的扇區大小是512位元組。

需要注意的是,無論是在記憶體中還是在磁碟中,區段的起始點和大小都必須符合相應的對齊值的整數倍!

我們來分析一下上面的圖,乙個程式的.text區段在磁碟檔案中的rva是0x1345,對齊值是0x1000,所以0x1345處的資料在區段內的偏移是0x345。

當這個程式被載入到記憶體中時,.text區段的對齊值被「拉長」到了0x2000,可以看到左邊圖中的區段起始點是0x402000,它邊上的陰影區就是與在磁碟中時區別的地方,段內偏移不變,還是0x345。

總結一下,載入到記憶體前,資料的偏移是0x1345,載入到記憶體後,資料的rva是0x2345。

以上說明了區段對齊,既然知道了rva需要轉為offset的原因,現在就可以學習轉為offset的方法了。

有個很重要的公式,即rva轉offset公式:

offset = (va-imagebase)-資料所在區段rva+資料所在區段offset

offset = rva-資料所在區段rva+資料所在區段offset

用上圖的例子套這個公式:

offset = 0x2345-0x2000+0x1000

rva = 0x1345 - 0x1000 + 0x2000

一般情況下dll檔案都有匯出表,匯出的都是dll檔案中的函式。生成匯出表的方法一般有兩種,一種是宣告extern 「c」 __declspec(dllexport) ,還有一種是.def檔案宣告。

因為本文只要著重講解匯出表的解析所以對於怎麼樣生成乙個帶匯出表的檔案就不做過多闡述了,畢竟這樣的文章網上到處都是,況且幾乎每乙個要被外部使用的dll檔案都有匯出表,我們只要在系統中隨便找乙個出來分析即可。

匯出表的結構體:

dword characteristics:未使用,對應上圖的0x00000000

dword timedatestamp:時間戳,檔案頭也有這個字段,對應上圖的0x4dc5f2dc

word majorversion:未使用,對應上圖的0x0000

word minorversion:未使用,對應上圖的0x0000

dword name:dll檔名rva,對應上圖的0x000025c0

base:匯出表的起始序號,一般是0x01。這個起始的序號的使用場景是:系統會利用呼叫序號,呼叫序號-起始序號(base)=函式原始序號,這個原始序號就是儲存在pe檔案中,也就是addressofnameordinals表中的序號。

為什麼要使用這個序號呢?這個需要詳細說說。匯出表中有3個陣列,分別是addressofoffunctions函式位址表、addressofnames函式名稱表、addressofnameordinals函式序號表,pe裝載器在載入檔案的時候,可以通過函式名稱表獲取函式名稱,但是無法與這個函式的位址建立聯絡,因此函式序號表就派上了用場,序號表跟名稱表的數量是絕對一樣並且一一對應的,因此裝載器在獲取到函式名時就可以獲取到序號了,這個序號也就是呼叫序號,用它減去起始序號也就是base得到的就是原始序號,這個原始序號對應函式位址表中的位置,因此就可以將函式名和函式位址對應起來了。對應上圖的0x00000001

dword numberofnames:函式名稱表中的個數,函式序號表中的個數因為跟名稱表中絕對一致,所以沒有必要弄出乙個專門的字段記錄序號表的個數,對應上圖的0x00000004

dword addressofnames:函式名稱表rva,儲存函式名字串所在的位址,這個rva轉換得到的offset處仍然是乙個rva,再將這個rva轉換得到的offset處還是乙個rva,最後再轉一次得到的offset處存的就是函式的名稱陣列,每個元素以00結尾,對應上圖的0x000025a8

dword addressofnamesordinals: 函式序號表rva,序號表陣列每個元素2個位元組,對應上圖的0x000025b8

PE 檔案格式學習

以前總在網上看看介紹pe檔案格式的文章,看的時候看到一大堆的結構體就蛋疼了,想想現在我這個居然都不清楚以後咋裝bi呢 今天下了個peview邊看變學了 先自己隨便寫個控制台程式,然後加進去就有了,讓後我們可以看看這個檔案到底是怎麼組成的。從這個樹形結構我們能很清楚的理解這個檔案的整體構成,在網上有很...

PE檔案格式

pe 的意思是 portable executable 可移植的執行體 它是 win32環境自身所帶的執行檔案格式。它的一些特性繼承自unix的coff common object file format 檔案格式。portable executable 可移植的執行體 意味著此檔案格式是跨win3...

PE檔案格式

pe檔案格式分析及修改 圖 1 2009 01 09 14 08 pe 的意思是 portable executable 可移植的執行體 它是 win32環境自身所帶的執行檔案格式。它的一些特性繼承自unix的coff common object file format 檔案格式。portable ...