PE文件格式解析學(xué)習(xí)筆記(3)---PE Header(IMAGE_NT_HEADERS部分)

NT Header(Ⅱ)

NT Header是主要包含三大部分內(nèi)容PE標(biāo)志(PE Signature),PE文件頭(PE_HEADER),PE可選頭(OPTION_PE_HEADER)

PE文件格式概覽

圖片轉(zhuǎn)自:https://blog.csdn.net/evileagle/article/details/11693499

PE可選頭

PE可選頭作為NT頭的最后一部分,也是定義字段最多,占據(jù)存儲(chǔ)最多的一部分結(jié)構(gòu)體定義的頭部信息,在定義的結(jié)構(gòu)體中一般分為兩種32位PE可選頭或者64位可選頭
32位PE可選頭,定義結(jié)構(gòu)體為typedef struct _IMAGE_NT_HEADERS占據(jù)大小為224Byte,31個(gè)字段
64位PE可選頭,定義結(jié)構(gòu)體為typedef struct _IMAGE_NT_HEADERS64占據(jù)大小為240Byte

32位PE可選頭

typedef struct _IMAGE_OPTIONAL_HEADER 
{
+0x00    WORD    Magic;         
+0x02   BYTE      MajorLinkerVersion;     
+0x03   BYTE      MinorLinkerVersion;     
+0x04   DWORD   SizeOfCode;     
+0x08    DWORD   SizeOfInitializedData;   
+0x0C    DWORD   SizeOfUninitializedData; 
+0x10    DWORD   AddressOfEntryPoint;    // 程序執(zhí)行入口RVA
+0x14    DWORD   BaseOfCode;      // 代碼的區(qū)塊的起始RVA
+0x18    DWORD   BaseOfData;      // 數(shù)據(jù)的區(qū)塊的起始RVA
+0x1C    DWORD   ImageBase;      // 程序的首選裝載地址
+0x20   DWORD   SectionAlignment;     
+0x24   DWORD   FileAlignment;     
+0x28    WORD    MajorOperatingSystemVersion; 
+0x2A    WORD    MinorOperatingSystemVersion;  
+0x2C    WORD    MajorImageVersion;       
+0x2E    WORD    MinorImageVersion;      
+0x30    WORD    MajorSubsystemVersion; 
+0x32    WORD    MinorSubsystemVersion;  
+0x34    DWORD   Win32VersionValue;       
+0x38    DWORD   SizeOfImage;       
+0x3C    DWORD   SizeOfHeaders;      
+0x40    DWORD   CheckSum;       
+0x44    WORD    Subsystem;      
+0x46    WORD    DllCharacteristics;      
+0x48    DWORD   SizeOfStackReserve;      
+0x4C    DWORD   SizeOfStackCommit;       
+0x50    DWORD   SizeOfHeapReserve;        
+0x54    DWORD   SizeOfHeapCommit;        
+0x58    DWORD   LoaderFlags;       
+0x5C    DWORD   NumberOfRvaAndSizes;     
+0x60    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
PE-Option-Header定義重要關(guān)鍵字段[12個(gè)]詳解(共計(jì)224Byte)
字段 含義 大小 成員位置
Magic 識(shí)別可執(zhí)行程序32位或64位 2Byte 1
AddressOfEntryPoint 程序入口地址 4Byte 7
ImageBase 內(nèi)存鏡像基址 4Byte 10
SectionAlignment 內(nèi)存對(duì)齊 4Byte 11
FileAlignment 文件對(duì)齊 4Byte 12
SizeOfImage 內(nèi)存中整個(gè)PE文件,就是PE文件展開后大小,是內(nèi)存對(duì)齊整數(shù)倍 2Byte 20
SizeOfHeaders PE文件的所有頭部之和大小,是文件對(duì)齊整數(shù)倍 4Byte 21
CheckSum 系統(tǒng)重要的dll會(huì)有,判斷文件是否被進(jìn)行修改 4Byte 22
SizeOfStackReserve 初始化保留棧的大小 4Byte 25
SizeOfStackCommit 初始化時(shí)實(shí)際提交棧的大小 4Byte 26
SizeOfHeapReserve 初始化保留堆的大小 4Byte 27
SizeOfHeapCommit 初始化時(shí)實(shí)際提交堆的大小 4Byte 28
Magic字段補(bǔ)充說明

常見的一些Magic字段取值說明,均為小端存儲(chǔ) PE32(10B): [0B 10] PE32+(20B): [0B 20]

程序入口補(bǔ)充說明

真實(shí)的入口地址 ==(內(nèi)存鏡像基址)ImageBase+(程序入口地址)AddressOfEntryPoint
其中ImageBase屬于相對(duì)虛擬地址(RVA),在內(nèi)存中開始位置距離.程序的首選裝載地址,如代碼區(qū)中注釋部分內(nèi)容所示

對(duì)齊相關(guān)內(nèi)容補(bǔ)充

對(duì)齊主要包括兩大部分內(nèi)存對(duì)齊以及文件對(duì)齊

  • 內(nèi)存對(duì)齊

內(nèi)存對(duì)齊原因:
1. 為了程序可移植性,在某些平臺(tái)只能在特定的地址處訪問特定類型的數(shù)據(jù),為了更好的兼容不同平臺(tái)
2. 數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能在自然邊界上對(duì)齊。
3. 為了訪問未對(duì)齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問;而未對(duì)齊的內(nèi)存僅需要訪問一次

內(nèi)存對(duì)齊原理:先查看C語言代碼及其執(zhí)行結(jié)果

#include <stdio.h>

struct test
{
char x1;
short x2;
float x3;
char x4;
}TEST;
struct test2
{
float x1;
short x2;
char x3;
char x4;
}TEST2;
void main()
{   
    test t1;
    test2 t2;
    printf("this test size of : %d\n",sizeof(t1));
    printf("this test start address : %x\n",&t1);
    printf("this test2 size of : %d\n",sizeof(t2));
    printf("this test2 start address : %x\n",&t2);
}

執(zhí)行結(jié)果如下圖:


執(zhí)行結(jié)果

可以從結(jié)果發(fā)現(xiàn),兩個(gè)結(jié)構(gòu)體的成員變量都是只有2個(gè)char類型,1個(gè)short類型,1個(gè)float類型,但是得到的結(jié)構(gòu)體大小不一致,這就是由于內(nèi)存對(duì)齊導(dǎo)致的結(jié)果
為了探究內(nèi)存對(duì)齊原理,可以通過查看內(nèi)存地址的數(shù)據(jù),以及反匯編調(diào)試進(jìn)行,為了方便,我打出來了相關(guān)的存儲(chǔ)地址分別為0x0019ff24與0x0019ff1c,通過打斷點(diǎn)進(jìn)行調(diào)試分析,并對(duì)其進(jìn)行賦值來觀察內(nèi)存使用情況。

對(duì)t1變量在內(nèi)存中的地址分配分析

首先 根據(jù)輸出的內(nèi)存起始地址,找到變量,在執(zhí)行t1變量聲明時(shí),占用了12Byte,并且初始化為CC,就是漢字的"燙"
t1變量聲明
其次 逐個(gè)對(duì)t1變量的成員賦值,并同時(shí)觀察內(nèi)存數(shù)據(jù)
對(duì)x1成員進(jìn)行賦值
當(dāng)對(duì)x2變量進(jìn)行賦值時(shí)發(fā)現(xiàn),并未按照預(yù)期想的,緊挨x1變量內(nèi)存地址賦值,而是跳過1Byte進(jìn)行賦值,char明明只是占1Byte,但是通過調(diào)試容易發(fā)現(xiàn),好像是感覺上占2Byte
對(duì)x2成員進(jìn)行賦值
但是 又發(fā)現(xiàn)對(duì)x3變量賦值時(shí),并未跳轉(zhuǎn),緊挨這賦值
對(duì)x3成員進(jìn)行賦值
最后同樣的,x4成員賦值也是正常的。
對(duì)x4成員進(jìn)行賦值

通過上面追蹤分析,可以發(fā)現(xiàn),這就是產(chǎn)生結(jié)果為12Byte的原因。

同樣的再次跟蹤t2變量,及其成員賦值過程

首先 根據(jù)輸出的內(nèi)存起始地址,找到變量,在執(zhí)行t2變量聲明時(shí),占用了8Byte,并且初始化為CC,就是漢字的"燙"
t2變量初始化
由于第一個(gè)成員變?yōu)閒loat類型所以占據(jù)4Byte
對(duì)x1成員進(jìn)行賦值
第二個(gè)成員變?yōu)閟hort類型所以占據(jù)2Byte,且緊挨這第一個(gè)成員變量地址賦值
對(duì)x2成員進(jìn)行賦值
由于第三個(gè)成員變?yōu)閏har類型緊挨第二個(gè)賦值為B
對(duì)x3成員進(jìn)行賦值
最后一個(gè)成員依舊緊挨賦值為B
對(duì)x4成員進(jìn)行賦值

通過對(duì)比,不難發(fā)現(xiàn),變量聲明的順序會(huì)導(dǎo)致結(jié)構(gòu)體大小不一致,第一個(gè)結(jié)構(gòu)體變量明顯存在未使用的內(nèi)存空間,從而導(dǎo)致空間浪費(fèi)。這些都是由于內(nèi)存對(duì)齊機(jī)制所導(dǎo)致,機(jī)制原理主要是起始的內(nèi)存地址必須是該類型變量所占內(nèi)存大小的整數(shù)倍,例如t1的x2成員為short占2Byte,所以需要從第2,4,6等2的整數(shù)倍地方開始存儲(chǔ)數(shù)據(jù)內(nèi)存,這就是內(nèi)存對(duì)齊機(jī)制。

  • 文件對(duì)齊
    文件對(duì)齊,主要是用來控制PE擴(kuò)展頭部,后面每一個(gè)Section的磁盤對(duì)齊的因子,必須遵守?cái)U(kuò)展為該因子的整數(shù)倍。
綜上所述PE擴(kuò)展文件頭32位,大小固定且為224Byte,共31大成員字段。其中關(guān)鍵字段成員為以上12大字段成員內(nèi)容。

繼續(xù)以Kernel32.dll進(jìn)行分析


PE擴(kuò)展頭部
字段 數(shù)值(小端存儲(chǔ)) 含義
Magic 0B01 PE為32位
AddressOfEntryPoint 705F0100 程序入口地址確定為0010F570
ImageBase 0000806B 內(nèi)存鏡像基址為6B800000
SectionAlignment 00000100 內(nèi)存對(duì)齊大小單位為0x00010000H
FileAlignment 00100000 文件對(duì)齊大小單位為0x00001000H
SizeOfImage 00000000 PE文件內(nèi)存展開后大小為0x00000000H
SizeOfHeaders 00000E00 PE文件的所有頭部之和大小為0x000E0000H
CheckSum 00100000 校驗(yàn)和為00100000
SizeOfStackReserve 03004041 初始化保留棧的大小0x41400003
SizeOfStackCommit 00000400 實(shí)際提交棧的大小為0x00400000
SizeOfHeapReserve 00100000 初始化保留堆的大小0x00001000
SizeOfHeapCommit 00001000 實(shí)際提交堆的大小為0x00100000
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容