結構體源代碼如下: typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // +18h WORD Magic; // 標誌字, ROM 映像(0107h),普通可執行文件(010Bh) +1Ah BYTE MajorLinke... ...
結構體源代碼如下:
typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // +18h WORD Magic; // 標誌字, ROM 映像(0107h),普通可執行文件(010Bh) +1Ah BYTE MajorLinkerVersion; // 鏈接程式的主版本號 +1Bh BYTE MinorLinkerVersion; // 鏈接程式的次版本號 +1Ch DWORD SizeOfCode; // 所有含代碼的節的總大小 +20h DWORD SizeOfInitializedData; // 所有含已初始化數據的節的總大小 +24h DWORD SizeOfUninitializedData; // 所有含未初始化數據的節的大小 +28h DWORD AddressOfEntryPoint; // 程式執行入口RVA ***(必須瞭解)*** +2Ch DWORD BaseOfCode; // 代碼的區塊的起始RVA +30h DWORD BaseOfData; // 數據的區塊的起始RVA // // NT additional fields. 以下是屬於NT結構增加的領域。 // +34h DWORD ImageBase; // 程式的首選裝載地址 ***(必須瞭解)*** +38h DWORD SectionAlignment; // 記憶體中的區塊的對齊大小 ***(必須瞭解)*** +3Ch DWORD FileAlignment; // 文件中的區塊的對齊大小 ***(必須瞭解)*** +40h WORD MajorOperatingSystemVersion; // 要求操作系統最低版本號的主版本號 +42h WORD MinorOperatingSystemVersion; // 要求操作系統最低版本號的副版本號 +44h WORD MajorImageVersion; // 可運行於操作系統的主版本號 +46h WORD MinorImageVersion; // 可運行於操作系統的次版本號 +48h WORD MajorSubsystemVersion; // 要求最低子系統版本的主版本號 +4Ah WORD MinorSubsystemVersion; // 要求最低子系統版本的次版本號 +4Ch DWORD Win32VersionValue; // 莫須有欄位,不被病毒利用的話一般為0 +50h DWORD SizeOfImage; // 映像裝入記憶體後的總尺寸 +54h DWORD SizeOfHeaders; // 所有頭 + 區塊表的尺寸大小 +58h DWORD CheckSum; // 映像的校檢和 +5Ch WORD Subsystem; // 可執行文件期望的子系統 ***(必須瞭解)*** +5Eh WORD DllCharacteristics; // DllMain()函數何時被調用,預設為 0 +60h DWORD SizeOfStackReserve; // 初始化時的棧大小 +64h DWORD SizeOfStackCommit; // 初始化時實際提交的棧大小 +68h DWORD SizeOfHeapReserve; // 初始化時保留的堆大小 +6Ch DWORD SizeOfHeapCommit; // 初始化時實際提交的堆大小 +70h DWORD LoaderFlags; // 與調試有關,預設為 0 +74h DWORD NumberOfRvaAndSizes; // 下邊數據目錄的項數,這個欄位自Windows NT 發佈以來一直是16 +78h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 數據目錄表 ***(必須瞭解,重點)*** winNT發佈到win10,IMAGE_NUMBEROF_DIRECTORY_ENTRIES一直都是16 } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
AddressOfEntryPoint ***(必須瞭解)***
程式開始執行的地址,這是一個RVA(相對虛擬地址)。對於exe文件,這裡是啟動代碼;對於dll文件,這裡是libMain()的地址。如果在一個可執行文件上附加了一段代碼並想讓這段代碼首先被執行,那麼只需要將這個入口地址指向附加的代碼就可以了。在脫殼時第一件事就是找入口點,指的就是這個值。
ImageBase ***(必須瞭解)***
PE文件的優先裝入地址。也就是說,當文件被執行時,如果可能的話(當前地址沒有被使用),Windows優先將文件裝入到由ImageBase欄位指定的地址中。
對於EXE文件來說,由於每個文件總是使用獨立的虛擬地址空間,優先裝入地址不可能被**模塊占據,所以EXE總是能夠按照這個地址裝入。
這也意味著EXE文件不再需要重定位信息。
對於DLL文件來說,由於多個DLL文件全部使用宿主EXE文件的地址空間,不能保證優先裝入地址沒有被**的DLL使用,所以DLL文件中必須包含重定位信息以防萬一。
因此,在前面介紹的 IMAGE_FILE_HEADER 結構的 Characteristics 欄位中,DLL 文件對應的 IMAGE_FILE_RELOCS_STRIPPED 位總是為0,而EXE文件的這個標誌位總是為1。
如果沒有指定的話,dll文件預設為0x10000000;exe文件預設為0x00400000,但是在Windows CE平臺上是0x00010000。此值必須是64K bytes的倍數!
SectionAlignment ***(必須瞭解)***
記憶體中區塊的對齊單位。區塊總是對齊到這個值的整數倍。此欄位必須大於或等於 FileAlignment ,預設值是系統頁面的大小。32位cpu通常值為 0x1000(十六進位),即4096,即4KB。64位cpu通常為 8kB
FileAlignment ***(必須瞭解)***
pe文件中區塊的對齊單位,以bytes(位元組)為單位。此值必須是2的次方倍,但是必須在512和64K區間之間(閉區間[521, 64*1024=65536]),如果SectionAlignment小於系統頁面的大小,那麼SectionAlignment的大小就和FileAlignment相同。pe文件中預設值為 521 位元組(0.5KB) 即 0x200(十六進位)。
Subsystem ***(必須瞭解)***
pe文件的用戶界面使用的子系統類型。定義如下:
#define IMAGE_SUBSYSTEM_UNKNOWN 0 // 未知子系統 #define IMAGE_SUBSYSTEM_NATIVE 1 // 不需要子系統(如驅動程式) #define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Windows GUI 子系統 #define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Windows 控制檯子系統 #define IMAGE_SUBSYSTEM_OS2_CUI 5 // OS/2 控制檯子系統 #define IMAGE_SUBSYSTEM_POSIX_CUI 7 // Posix 控制檯子系統 #define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 // 鏡像是原生 Win9x 驅動程式 #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 // Windows CE 圖形界面
例如,Visual Studio 2015中編譯程式時可以在圖形界面設置鏈接選項:
更多請查看:
微軟官方文檔:https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx
DataDirectory ***(必須瞭解,重要)***
這個欄位可以說是最重要的欄位之一,它由16個相同的IMAGE_DATA_DIRECTORY結構組成。其結構如下:
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress; // 相對虛擬地址
DWORD Size; // 數據塊的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
也就是定義了某塊的位置和大小。
雖然PE文件中的數據是按照裝入記憶體後的頁屬性歸類而被放在不同的節中的,但是這些處於各個節中的數據按照用途可以被分為導出表、導入表、資源、重定位表等數據塊,這16個IMAGE_DATA_DIRECTORY結構就是用來定義多種不同用途的數據塊的(如下表所示)。IMAGE_DATA_DIRECTORY結構的定義很簡單,它僅僅指出了某種數據塊的位置和長度。
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // 導出表 #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // 導入表 #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // 資源表 #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // 異常表(具體資料不詳) #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // 安全表(具體資料不詳) #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // 重定位表 #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // 調試表 // IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage) 版權信息 #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // 版權信息 #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP (具體資料不詳) #define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory (線程位置存儲,具體資料不詳) #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory (不詳) #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers(不詳) #define IMAGE_DIRECTORY_ENTRY_IAT 12 // 導入函數地址表 #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors(不詳) #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor(不詳)