PE文件

電腦通訊 9547 504 2014-11-23

PE文件指的是可移植可執行(Portable Executable)文件。這些文件通常是DLL和EXE文件。一個 PE 文件中可以有多個命名空間,也可以包括嵌套的命名空間。而一個命名空間可以拆分到多個 PE 文件。一個或多個 PE 文件(可能還有其它非PE文件,如資源文件)可以組合在一起創建程序集。程序集是可部署、可進行版本編號和可復用的物理單元。

PE文件格式的概要:

DOS MZ header

DOS stub

PE header

Section table

Section 1

Section 2

Section ...

Section n

PE文件結構的總體層次分佈。所有 PE文件(甚至32位的 DLLs) 必須以一個簡單的 DOS MZ header 開始。我們通常對此結構沒有太大興趣。有了它,一旦程序在DOS下執行,DOS就能識別出這是有效的執行體,然後運行緊隨 MZ header 之後的 DOS stub。DOS stub實際上是個有效的 EXE,在不支持 PE文件格式的操作系統中,它將簡單顯示一個錯誤提示,類似於字符串 "This program requires Windows" 或者程序員可根據自己的意圖實現完整的 DOS代碼。通常我們也不對 DOS stub 太感興趣:因為大多數情況下它是由彙編器/編譯器自動生成。通常,它簡單調用中斷21h服務9來顯示字符串"This program cannot run in DOS mode"。

緊接著 DOS stub 的是 PE header。PE header 是PE相關結構 IMAGE_NT_HEADERS 的簡稱,其中包含了許多PE裝載器用到的重要域。當我們更加深入研究PE文件格式後,將對這些重要域耳目能詳。執行體在支持PE文件結構的操作系統中執行時,PE裝載器將從 DOS MZ header 中找到 PE header 的起始偏移量。因而跳過了 DOS stub 直接定位到真正的文件頭 PE header。

PE文件的真正內容劃分成塊,稱之為sections(節)。每節是一塊擁有共同屬性的數據,比如代碼/數據、讀/寫等。我們可以把PE文件想像成一邏輯磁盤,PE header 是磁盤的boot扇區,而sections就是各種文件,每種文件自然就有不同屬性如只讀、系統、隱藏、文檔等等。值得我們注意的是----節的劃分是基於各組數據的共同屬性:而不是邏輯概念。重要的不是數據/代碼是如何使用的,如果PE文件中的數據/代碼擁有相同屬性,它們就能被歸入同一節中。不必關心節中類似於"data","code"或其他的邏輯概念:如果數據和代碼擁有相同屬性,它們就可以被歸入同一個節中。(譯者註:節名稱僅僅是個區別不同節的符號而已,類似"data","code"的命名只為了便於識別,惟有節的屬性設置決定了節的特性和功能)如果某塊數據想付為只讀屬性,就可以將該塊數據放入置為只讀的節中,當PE裝載器映射節內容時,它會檢查相關節屬性並置對應內存塊為指定屬性。

如果我們將PE文件格式視為一邏輯磁盤,PE header是boot扇區而sections是各種文件,但我們仍缺乏足夠信息來定位磁盤上的不同文件,譬如,什麼是PE文件格式中等價於目錄的東東?別急,那就是 PE header 接下來的數組結構 section table(節表)。每個結構包含對應節的屬性、文件偏移量、虛擬偏移量等。如果PE文件裡有5個節,那麼此結構數組內就有5個成員。因此,我們便可以把節表視為邏輯磁盤中的根目錄,每個數組成員等價於根目錄中目錄項。

以上就是PE文件格式的物理分佈,下面將總結一下裝載一PE文件的主要步驟:

當PE文件被執行,PE裝載器檢查 DOS MZ header 裡的 PE header 偏移量。如果找到,則跳轉到 PE header。

PE裝載器檢查 PE header 的有效性。如果有效,就跳轉到PE header的尾部。

緊跟 PE header 的是節表。PE裝載器讀取其中的節信息,並採用文件映射方法將這些節映射到內存,同時付上節表裡指定的節屬性。

PE文件映射入內存後,PE裝載器將處理PE文件中類似 import table(引入表)邏輯部分。

上述步驟是基於本人觀察後的簡述,顯然還有一些不夠精確的地方,但基本明晰了執行體被處理的過程。

你應該下載 LUEVELSMEYER的《PE文件格式》。該文的描述相當詳細,可用作案頭的參考手冊。

下載地址:點擊下載PE文件格式



,