PE檔案格式總結
- 基本介紹
- 1.DOS Header 和 DOS stub
- 2.NT headers
-
- 2.1File header
- 2.2 Optional header
- 3.Section headers
- 4.Sections
- 其他
時間:202106
基本介紹
PE檔案主要由 檔案頭 和 區段(Section) 構成(如圖所示),檔案頭記錄相關資訊,而區段則存放相關資料。相連代表資料在檔案中存儲緊接上一部分。
檔案頭部分包括:
(1) DOS Header
(2) DOS Stub
(3) NT Headers
(4) Section Headers
運作時PE檔案由PE加載器加載到記憶體,檔案頭部分将會被加載到 記憶體基址(Image Base) 。但程式運作時一般會加載多個子產品,如果都固定 Image Base 可能會導緻記憶體使用沖突,是以PE檔案會設定一個首選 Image Base,但實際的 Image Base 由 PE 加載器決定。是以,PE 檔案中一般不使用絕對的記憶體位址,而采用相對于 Image Base 偏移的位址,稱為 相對記憶體位址(Relative Virtual Address, RVA) ,其 絕對記憶體位址(Virtual Address, VA) 在加載後計算得到,關系如下:
VA = ImageBase + RVA
區段頭(Section Header) 中包括了該區段的重要資訊,主要包括:區段資料的檔案位置和大小、加載到記憶體時的 RVA 和占用記憶體大小、區段屬性。PE加載器通過讀取區段頭的資訊,将檔案中的區段資料加載到對應的記憶體位址中。檔案中的位置由相對檔案第一個位元組的偏移描述,稱為 檔案偏移位址(File Offset Address, FOA)。
1.DOS Header 和 DOS stub
DESC (Description) : 為相容 ms-dos 系統而存在,DOS stub 為 DOS 根存程式。
FOA : 0x00000000
e_magic
DESC : 辨別符, 必須為 ”MZ”, 0x5A4D。
e_lfanew
DESC : 新檔案頭 NT headers 的 FOA 。
2.NT headers
DESC : PE 檔案頭。
FOA : IMAGE_DOS_HEADER.elfanew
Signature
DESC : 辨別符, 必須為 ”PE”,0x00004550。
2.1File header
FOA : IMAGE_DOS_HEADER.elfanew + 0x04
Machine
DESC : 辨別符,映像檔案适用的機器類型。
值 | 描述 |
---|---|
0x014C | x86 處理器 |
0x0200 | Intel Itanium 處理器 |
0x8664 | x64 處理器 |
TimeDateStamp
DESC : 檔案的建立時間,等于 1970/01/01 00:00:00 起經過的秒數。
SizeOfOptionalHeader
DESC : Optional Header 的大小,值可以為 224 位元組和 240 位元組,分别表示 32 位和 64 位。該值可以作為 32 位/ 64 位的判斷依據。
Characteristics
DESC : 檔案屬性。
位 | 描述 |
---|---|
0x0001 | 重新定位資訊已從檔案中删除,檔案必須在其首選基址處加載,如果基位址不可用,加載器會報錯 |
0x0002 | 檔案可執行 |
0x0004 | COFF line number 已經從檔案中删除 |
0x0008 | COFF 符号表條目已經從檔案中删除 |
0x0010 | 棄用 |
0x0020 | 應用程式可以處理大于 2GB 的位址 |
0x0080 | 保留 |
0x0100 | 計算機支援 32 位體系架構 |
0x0200 | 調試資訊被移除并儲存在另一個檔案中 |
0x0400 | 如果此鏡像檔案在可移動媒體上,将其複制到交換檔案中并從中運作 |
0x0800 | 如果此鏡像檔案在網絡媒體上,将其複制到交換檔案中并從中運作 |
0x1000 | 此鏡像檔案是系統檔案 |
0x2000 | 此鏡像檔案是動态連結庫 (DLL) |
0x4000 | 此檔案隻能運作于單處理器機器上 |
0x8000 | 保留 |
值未列出表明官方文檔缺失,之後的表格也是如此
2.2 Optional header
FOA : IMAGE_DOS_HEADER.elfanew + 0x18
Magic
DESC : 辨別符。
值 | 描述 |
---|---|
0x10B | 檔案為 32 位程式的可執行映像 |
0x20B | 檔案為 64 位程式的可執行映像 |
0x107 | 檔案為 ROM 映像。 |
SizeOfCode
SizeOfInitializedData
SizeOfUninitializedData
DESC : 代碼段、已初始化和未初始化的資料段的位元組大小,如果存在多個段則為所有段大小之和。
每個 Section 在檔案中的資料都為已初始化的資料,可以直接加載到記憶體中。
未初始化資料應該是用于減小檔案的大小,具體是:如果檔案中 Section 某位置一直到該 Section 結束時的資料初始值均為 0x00,就可以将該部分删去,而 Section 加載到記憶體時的實際大小設定不變,加載時僅加載 Section 在檔案中有的部分,剩下的記憶體則由PE加載器填充 0x00,即由PE加載器完成初始化工作。
AddressOfEntryPoint
DESC : 程式入口點相對于 ImageBase 的偏移位址,即入口點的 RVA。
ImageBase
DESC : 映像被加載到記憶體時第一個位元組的首選基址, 值為 64KB 的倍數。Dll 預設為 0x10000000; 應用程式除了在 Windows CE 上為預設為 0x00010000,其他預設為 0x00400000。
當加載到記憶體後, PE裝載器會将其修改為實際加載的基址。
SectionAlignment
DESC : 區段加載到記憶體時的對齊位元組值,即加載到 SectionAlignment 倍數的記憶體位址處。該值必須不小于 FileAlignment,預設值為系統的頁大小 (4KB)。是以記憶體中相鄰 Section 間一般存在間隙。
FileAlignment
DESC : 區段資料在映像檔案中的對齊位元組值。該值為 512 到 64K 之間 2 的幂(含邊界值),預設值為 512 位元組。是以每個區段末一般會有填充 0x00 的部分,且未被使用。
SizeOfImage
DESC : 映像加載到記憶體後占用的總大小,值必須為 SectionAlignment 的倍數。
SizeOfHeaders
DESC : 檔案頭的大小,為以下幾個值的和,且最終向上舍入到 FileAlignment 的倍數。
a) IMAGE_DOS_HEADER.e_lfanew
b) 4位元組的辨別符
c) IMAGE_FILE_HEADER 的大小
d) 可選頭的大小
e) 所有區段頭的大小
CheckSum
DESC : 校驗和,在以下檔案加載時驗證:所有驅動程式、任何引導時加載的 DLL 和任何加載到關鍵系統程序中的 DLL。
Subsystem
DESC : 運作該映像所需要的子系統類型。
值 | 描述 |
---|---|
未知子系統 | |
1 | 無子系統要求(裝置驅動程式和本地系統程序) |
2 | Windows 圖形使用者界面 (GUI) 子系統 |
3 | Windows 字元模式使用者界面 (CUI) 子系統 |
5 | OS/2 CUI 子系統 |
7 | POSIX CUI 子系統 |
9 | Windows CE 子系統 |
10 | 可擴充固件接口 (EFI) 應用程式 |
11 | 帶引導服務的 EFI 驅動 |
12 | 帶運作時服務的 EFI 驅動 |
13 | EFI ROM 映像 |
14 | Xbox 子系統 |
DllCharacteristics
DESC : Dll 屬性。
位 | 描述 | |
32 位 | 64 位 | |
0x0001 | 保留 | |
0x0002 | 保留 | |
0x0004 | 保留 | |
0x0008 | 保留 | |
0x0020 | 具有64位位址空間的ASLR | 無文檔資訊 |
0x0040 | DLL 可以在加載時重新定位 | |
0x0080 | 強制進行代碼完整性校驗 | |
0x0100 | 映像與資料執行保護 (DEP) 相容 | |
0x0200 | 映像可以隔離,但不應該隔離 | |
0x0400 | 映像不使用結構化異常處理 (SHE),無法在映像中調用任何處理程式 | |
0x0800 | 不綁定映像 | |
0x1000 | 映像應該在 AppContainer 中執行 | 保留 |
0x2000 | WDM 驅動 | |
0x4000 | 映像支援控制流保護 | 保留 |
0x8000 | 映像支援終端伺服器 |
SizeOfStackReserve
SizeOfStackCommit
DESC : 棧保留大小和棧送出大小。棧在加載時僅使用 SizeOfStackCommit 大小的記憶體, 剩餘的在達到棧保留大小前每次僅使用一頁。
SizeOfHeapReserve
SizeOfHeapCommit
DESC : 堆保留大小和堆送出大小。堆在加載時僅使用 SizeOfHeapCommit 大小的記憶體, 剩餘的在達到堆保留大小前每次僅使用一頁。
DataDirectory
DESC : 目錄表,為 IMAGE_DATA_DIRECTORY 結構體數組,共 16 個元素,描述相應表項的位置和大小資訊。
IMAGE_DATA_DIRECTORY.VirtualAddress 為表項内容的 RVA。
表項如下:
索引值 | 描述 |
---|---|
導出表 | |
1 | 導入表 |
2 | 資源目錄 |
3 | 異常目錄 |
4 | 安全目錄 |
5 | 基本重定位表 |
6 | 調試資訊目錄 |
7 | 特殊結構資料表 |
8 | 全局指針寄存器相對虛拟位址 |
9 | 線程局部儲存 (TLS) 表 |
10 | 加載配置表 |
11 | 綁定導入表 |
12 | 導入位址表 |
13 | 延遲導入描述 |
14 | CLR 頭 |
15 | 保留 |
3.Section headers
DESC : 區段表,由 IMAGE_SECTION_HEADER 結構體數組構成,每個元素描述一個區段的資訊,以 NULL 元素結束。
FOA : IMAGE_DOS_HEADER.elfanew + NT headers大小 (緊跟 NT headers)
Name
DESC : 區段名, 一個 8 位元組、0x00 填充的 UTF-8 字元串。
如果字元串長度正好為 8 個字元,則不存在 ’\0’ 終止符。如果名稱較長, 此成員值為 正斜杠 (/) + ASCII 表示的十進制數, 該十進制數為名稱在字元串表中的偏移量。可執行映像不使用字元串表,也不支援長度超過 8 個字元的區段名。
Misc.VirtualSize
DESC : 加載到記憶體時整個區段的實際大小, 如果值大于 SizeOfRawData , 說明有未初始化的資料,這部分将由 PE 加載器完成初始化。
僅可執行映像有效,對于 obj 檔案該值為 0。
VirtualAddress
DESC : 區段的 RVA。
對于 obj 檔案該值為重定位前的位址。
SizeOfRawData
DESC : 區段在磁盤上已初始化資料的大小。值必須為 IMAGE_OPTIONAL_HEADER.FileAlignment 的倍數。如果該值小于 Misc.VirtualSize,區段剩餘部分由 PE 加載器填充零,完成初始化。如果區段僅包含未初始化資料, 該值為 0。
PointerToRawData
DESC : 區段資料的 FOA, 值必須為 IMAGE_OPTIONAL_HEADER.FileAlignment 的倍數。如果區段僅包含未初始化資料, 該值為 0。
PointerToRelocations
PointerToLinenumbers
DESC : 區段的重定位項和行号項的檔案指針。如果沒有, 該值為 0。
NumberOfRelocations
NumberOfLinenumbers
DESC: 重定位項數和行号項數。
可執行映像的重定位項數為 0。
Characteristics
DESC : 區段的屬性。
值 | 描述 |
---|---|
0x00000000 | 保留 |
0x00000001 | 保留 |
0x00000002 | 保留 |
0x00000004 | 保留 |
0x00000008 | 棄用 |
0x00000010 | 保留 |
0x00000020 | 區段包含可執行代碼 |
0x00000040 | 區段包含已初始化資料 |
0x00000080 | 區段包含未初始化資料 |
0x00000100 | 保留 |
0x00000200 | 區段包含注釋或其他資訊, 僅對 obj 檔案有效 |
0x00000400 | 保留 |
0x00000800 | 區段不會成為映像一部分, 僅對 obj 檔案有效 |
0x00001000 | 區段包含 COMDAT 資料, 僅對 obj 檔案有效 |
0x00002000 | 保留 |
0x00004000 | 重置 TLB 表的風險異常處理位 |
0x00008000 | 區段包含通過全局指針引用的資料 |
0x00010000 | 保留 |
0x00020000 | 保留 |
0x00040000 | 保留 |
0x00080000 | 保留 |
0x00100000 | 按1位元組對齊資料, 僅對 obj 檔案有效 |
0x00200000 | 按2位元組對齊資料, 僅對 obj 檔案有效 |
0x00300000 | 按4位元組對齊資料, 僅對 obj 檔案有效 |
0x00400000 | 按8位元組對齊資料, 僅對 obj 檔案有效 |
0x00500000 | 按16位元組對齊資料, 僅對 obj 檔案有效 |
0x00600000 | 按32位元組對齊資料, 僅對 obj 檔案有效 |
0x00700000 | 按64位元組對齊資料, 僅對 obj 檔案有效 |
0x00800000 | 按128位元組對齊資料, 僅對 obj 檔案有效 |
0x00900000 | 按256位元組對齊資料, 僅對 obj 檔案有效 |
0x00A00000 | 按512位元組對齊資料, 僅對 obj 檔案有效 |
0x00B00000 | 按1024位元組對齊資料, 僅對 obj 檔案有效 |
0x00C00000 | 按2048位元組對齊資料, 僅對 obj 檔案有效 |
0x00D00000 | 按4096位元組對齊資料, 僅對 obj 檔案有效 |
0x00E00000 | 按8192位元組對齊資料, 僅對 obj 檔案有效 |
0x01000000 | 區段包含擴充重定位 |
0x02000000 | 可以根據需要丢棄該區段 |
0x04000000 | 區段不能被緩存 |
0x08000000 | 區段不能分頁 |
0x10000000 | 區段在記憶體中可共享 |
0x20000000 | 區段可執行 |
0x40000000 | 區段可讀 |
0x80000000 | 區段可寫 |
4.Sections
DESC: 每個區段在檔案中的資料(已初始化資料),大小為相應區段表項的 IMAGE_SECTION_HEADER. SizeOfRawData 值。
FOA : 區段表各項的 PointerToRawData 成員值。
區段在檔案中的資料為已初始化資料 (這裡暫時将可執行代碼也視為已初始化資料),因為對齊要求必須為 IMAGE_OPTIONAL_HEADER. FileAlignment 的倍數,是以檔案中區段末尾一般存在編譯時填充的 0x00 位元組,而 Section Header 中 Misc.VirtualSize 值通常沒有包括這部分填充的初始化資料。但 Misc.VirtualSize 值還包括了未初始化資料大小,是以他們的值在不同情況下有不同大小關系。
IMAGE_SECTION_HEADER.SizeOfRawData = 已初始化資料(含填充資料)大小
IMAGE_SECTION_HEADER.Misc.VirtualSize = 已初始化資料(一般不含填充資料)大小 + 未初始化資料大小
其他
通過 RVA 确定其 FOA 的方法:
a) 分析 Section Headers 确定各區段資料的 RVA 範圍和 FOA 範圍。
b) 比較已知 RVA 和各區段 RVA 範圍,确定已知 RVA 屬于哪個區段。
c) 計算已知 RVA 相對于該區段起始 RVA 的偏移值 Offset。
d) 已知 RVA 對應的 FOA 為該區段起始 FOA 加上一步得到的 Offset。