一:DOS部分
DOS部分分為DOS MZ文件頭和DOS塊,其中DOS MZ頭實際是一個64位的IMAGE_DOS——HEADER結構體。
DOS MZ頭部結構體的內容如下,我們所需要關注的是前面兩個字節(e_magic)和后面四個字節(e_lfanew)
typedef struct _IMAGE_DOS_HEADER
{WORD e_magic; // DOS頭的標識 "MZ" 4Dh 5Ah(2個字節) #define IMAGE_DOS_SIGNATURE 0x5A4DWORD e_cblp; // 文件最后一頁中的字節數WORD e_cp; // 文件中的全部頁數WORD e_crlc; // 重定位表中的指針數WORD e_cparhdr; // 頭部尺寸,以段落為單位WORD e_minalloc; // 所需的最小附加段 WORD e_maxalloc; // 所需的最大附加段 WORD e_ss; // 初始的SS值(相對偏移量)WORD e_sp; // 初始的SP值WORD e_csum; // 補碼校驗值WORD e_ip; // 初始的IP值 WORD e_cs; // 初始的CS值WORD e_lfarlc; // 重定位表的字節偏移量 WORD e_ovno; // 覆蓋號WORD e_res[4]; // 保留字WORD e_oemid; // OEM 標識符(相對e_oeminfo) WORD e_oeminfo; // OEM 信息WORD e_res2[10]; // 保留字// DosHeader + 0x3C 正好定位到e_lfanewLONG e_lfanew; // NT頭相對于文件起始地址的偏移, 4字節, 指示NT頭的位置
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
二、PE文件頭
PE文件頭可以分為三個部分,分別為PE標識、標準PE頭、擴展PE頭,結構體內容如下所示
typedef struct _IMAGE_NT_HEADERS {DWORD Signature; ``// PE標識--4字節IMAGE_FILE_HEADER FileHeader; ``// 標準PE頭--20字節IMAGE_OPTIONAL_HEADER32 OptionalHeader; ``// 擴展PE頭--224字節/240字節
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
現在我們詳細解釋一下標準PE頭,標準PE頭的結構體如下:
typedef struct _IMAGE_FILE_HEADER
{WORD Machine; //PE文件運行的平臺,值為IMAGE_FILE_MACHINE_I386(0x14c)表示是x86處理器,//IMAGE_FILE_MACHINE_AMD64(0x8664)或IMAGE_FILE_MACHINE_IA64(0x200)表示是x64處理器。WORD NumberOfSections; //文件中存在的節的個數,如果想在PE文件中增加或刪除節,必須變更此處的值DWORD TimeDateStamp; //創建此文件時的時間戳DWORD PointerToSymbolTable; //COFF符號表的文件偏移,對于映像文件來說,此值為0DWORD NumberOfSymbols; //符號表中元素的數目,對于映像文件來說,此值為0WORD SizeOfOptionalHeader; //可選頭的大小,32位下默認為00E0h,64位下默認為00F0hWORD Characteristics; //文件屬性標志,exe一般是010fh,dll一般是210eh
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
現在我們得到:
那什么是PE文件屬性呢,現在我們知道PE文件屬性的十六進制值是00 22(倒序讀取),那么可以得到二進制是0001 0110
對應下面的表,也就是第1位、第二位和第四位對應數字為1得到的屬性值
對于擴展PE頭,大小有標準PE頭的SizeOfOptionalHeader決定,就是00F0
三、節表
每個節表的固定大小是40字節,節表不止一個,可能有多個,節表的數量是標準PE頭中的NumberOfSections屬性決定的,雖然節表有多個,但是每個節表中的結構是相同的。
根據上面的標準頭解析,可以看到是六個節表(00 06),每個節表大小是40字節,一共是240字節,如下圖
每個節表的最后四個字節是屬性,這里是60 00 00 20,可以得到二進制是0110 0000 0000 0000 0000 0000 0010 0000
那么就可以得到:
利用工具打開,可以發現是六個節表
以下是節表的基本結構
typedef struct _IMAGE_SECTION_HEADER {
0x00 BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //00 00 00 74 78 65 74 2E 8字節,節表的名字,一般情況下"\0"來結束,內容可以自己定義
union { 0x08 DWORD PhysicalAddress; 0x08 DWORD VirtualSize;
} Misc; //00 01 80 6C 雙字,是該節在沒有對齊前的真是尺寸,內容可以不準確
0x0c DWORD VirtualAddress; //00 00 10 00 節區在內存中的偏移地址
0x10 DWORD SizeOfRawData; //00 01 82 00 節在文件中對齊后的尺寸
0x14 DWORD PointerToRawData; //00 00 04 00 節區在文件中的偏移
0x18 DWORD PointerToRelocations; //00 00 00 00 在exe文件中無意義
0x1c DWORD PointerToLinenumbers; //00 00 00 00 在exe文件中無意義
0x20 WORD NumberOfRelocations; //00 00 在exe文件中無意義
0x22 WORD NumberOfLinenumbers; //00 00 該節在行號表中的行號數
0x24 DWORD Characteristics; //60 00 00 20 節的屬性
};
?四、節數據
查看區段:
我們需要的是節區在文件中的偏移,就是在20字節之后的00000400,節區的大小是在16字節之后的,也就是0046FE00
?也就是00000400之后的數據:
以上就是最基本的PE文件結構了。