近期太忙一直沒有抽出時間來更新文章,週末抽空寫一篇關於PE結構相關知識,PE結構是windows下的可執行文件的標準結構。可執行文件的裝載、內存分步、執行等都依賴於PE結構。如果要掌握反病毒、免殺、權益保護、反調試、加殼脫殼等相關知識,那瞭解PE結構則是重中之重。
一、PE結構概述
PE文件大致可以分爲兩部分,即數據管理結構及數據部分。數據管理結構包含:DOS頭、PE頭、節表。數據部分包括節表數據(節表數據是包含着代碼、數據等內容)。詳情見下圖:
1.DOS頭
DOS頭分爲兩個部分,分別是MZ頭及DOS存根,MZ頭是真正的DOS頭部,它的結構被定義爲IMAGE_DOS_HEADER。DOS存根是一段簡單程序,主要是用於兼容DOS程序,當不兼容DOS程序時,輸出:"this program cannot be run in DOS mode"。
2.PE頭
PE頭分爲三個部分,分別是PE標識(IMAGE_NT_SIGNATRUE)、文件頭(IMAGE_FILE_HEADER)、可選頭(IMAHE_OPTION_HEADER)。PE頭是固定不變的,位於DOS頭部中e_ifanew字段指出位置。
3.節表
程序中組織按照不同屬性存在不同的節中,如果PE中文件頭的NumberOfSections值中有N個節,那麼節表就是由N個節表(IMAGE_SECTION_HEADER)組成。節表主要是存儲了何種借的屬性、文件位置、內存位置等。位置緊跟PE頭後。
4.節表數據
PE文件真正程序部分的存儲位置,有幾個節表就有幾個節表數據,根據節表的屬性、地址等信息,程序的程序就分佈在節表的指定位置。位置緊跟節表後。
二、通過代碼進行詳解
我本地編寫了簡單的"hello word"的代碼。運行程序彈出"hello word"提示框。
2.1基礎環境介紹
具體代碼如下圖:
2.2 DOS頭介紹
這時我們通過c32asm查看該程序的二進制文件,詳情見下圖。
其中 5A 4D 十六進制爲MZ。(系統使用的是小尾存儲方式,所以需要倒序)。F8 00是DOS頭部的e_ifanew字段存儲的值。所以PE開頭位置位於上圖箭頭標示處,具體DOS頭部代碼定義,請見下圖(位於winnt.h頭文件下)。
其中的DOS存根就位於兩者之間,見下圖:
DOS存根部分經常由於各種需要而保存其它數據,因此可以進行填充,填充內容你可以自己想象啦。
2.3 PE頭介紹
PE在結構概述中,我們講到,PE頭分爲三個部分,分別是PE標識(IMAGE_NT_SIGNATRUE)、文件頭(IMAGE_FILE_HEADER)、可選頭(IMAHE_OPTION_HEADER)。PE標識佔4個字節,文件頭佔20個字節,可選頭的大小由文件頭的SizeOfOptionalHeader的值來確定。
PE標識見下圖:
文件頭標識見下圖:
其中 machine字段的值爲 4c 01,其代表可執行文件的目標CPU類型。
014c:intel;0184:DEC Alpha;0200:inter(64-bit);0284: DEC Alpha(64-bit)
characteristics字段的值爲0201即 0x0102,該值表示文件運行的目標爲32位平臺。
具體不過多介紹啦,有興趣的小夥伴自行查找吧~
可選頭標識見下圖:
由於可選頭大小由SizeOfOptionalHeader存儲的值確定,所以可選頭大小爲 0x00E0(十進制爲224),具體大小見下圖:
可選頭是文件頭的補充,主要用來管理PE文件被操作系統裝載時所需的信息。
2.4節表介紹
PE->可選頭結束後,即爲節表個數由PE中文件頭的NumberOfSections值中有N個節。本程序中NumberOfSections值爲9個,如下圖:
每個節表(IMAGE_SECTION_HEADER) 40個字節,所以總節表共9*40=360個字節。
name字段節名的長度爲8個字節,多餘會被截取,本示例中2E 74 65 78 74 000000爲".text",見下圖 。
黑客入口點通常在第一節區。
.text:V偏移:0x00001001;V大小:00004af0; R大小:0000 c400;R偏移;00000400;
.text段是代碼段
.data段是數據段。
bss段是全局變量數據段。
節表具體結構如下圖:
Name[IMAGE_SIZEOF_SHORT_NAME]; // 節表名稱,如“.text”
PhysicalAddress; // 物理地址
VirtualSize; // 真實長度
VirtualAddress; // 節區的 RVA 地址
SizeOfRawData; // 在文件中對齊後的尺寸
PointerToRawData; // 在文件中的偏移量
PointerToRelocations; // 在OBJ文件中使用,重定位的偏移
PointerToLinenumbers; // 行號表的偏移(供調試使用地)
NumberOfRelocations; // 在OBJ文件中使用,重定位項數目
NumberOfLinenumbers; // 行號表中行號的數目
Characteristics; // 節屬性如可讀,可寫,可執行等
關於PE結構對的三種存儲地址 VA;RVA;FILEOFFSET,以及如何進行定位我們下篇進行詳細介紹。