{
//
// 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];
// 數據目錄表
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
事實上,這個結構中的大部分字段都不重要,大家可以從注釋中理解它們的含義,小甲魚將比較重要的字段在下邊跟大家詳細講解。另外,這玩意千萬不要去背啊,我們要把絕大多數的時間拿來改變,而不是記住。不用做筆記,把這篇文章轉載到您的博客就行(最好注明:小甲魚是帥哥)吼 吼 ^_^
● AddressOfEntryPoint字段
指出文件被執行時的入口地址,這是一個RVA地址(RVA的含義在下一節中詳細介紹)。如果在一個可執行文件上附加了一段代碼並想讓這段代碼首先被執行,那么只需要將這個入口地址指向附加的代碼就可以了。
● ImageBase字段
指出文件的優先裝入地址。也就是說當文件被執行時,如果可能的話,Windows優先將文件裝入到由ImageBase字段指定的地址中,只有指定的地址已經被**模塊使用時,文件才被裝入到**地址中。鏈接器產生可執行文件的時候對應這個地址來生成機器碼,所以當文件被裝入這個地址時不需要進行重定位操作,裝入的速度最快,如果文件被裝載到**地址的話,將不得不進行重定位操作,這樣就要慢一點。
對於EXE文件來說,由於每個文件總是使用獨立的虛擬地址空間,優先裝入地址不可能被**模塊占據,所以EXE總是能夠按照這個地址裝入,這也意味着EXE文件不再需要重定位信息。對於DLL文件來說,由於多個DLL文件全部使用宿主EXE文件的地址空間,不能保證優先裝入地址沒有被**的DLL使用,所以DLL文件中必須包含重定位信息以防萬一。因此,在前面介紹的 IMAGE_FILE_HEADER 結構的 Characteristics 字段中,DLL 文件對應的 IMAGE_FILE_RELOCS_STRIPPED 位總是為0,而EXE文件的這個標志位總是為1。
在鏈接的時候,可以通過對link.exe指定/base:address選項來自定義優先裝入地址,如果不指定這個選項的話,一般EXE文件的默認優先裝入地址被定為00400000h,而DLL文件的默認優先裝入地址被定為10000000h。
● SectionAlignment 字段和 FileAlignment字段
SectionAlignment字段指定了節被裝入內存后的對齊單位。也就是說,每個節被裝入的地址必定是本字段指定數值的整數倍。而FileAlignment字段指定了節存儲在磁盤文件中時的對齊單位。
● Subsystem字段
指定使用界面的子系統,它的取值如表17.3所示。這個字段決定了系統如何為程序建立初始的界面,鏈接時的/subsystem:**選項指定的就是這個字段的值,在前面章節的編程中我們早已知道:如果將子系統指定為Windows CUI,那么系統會自動為程序建立一個控制台窗口,而指定為Windows GUI的話,窗口必須由程序自己建立。
界面子系統的取值和含義
取 值 |
Windows.inc中的預定義值 |
含 義 |
0 |
IMAGE_SUBSYSTEM_UNKNOWN |
未知的子系統 |
1 |
IMAGE_SUBSYSTEM_NATIVE |
不需要子系統(如驅動程序) |
2 |
IMAGE_SUBSYSTEM_WINDOWS_GUI |
Windows圖形界面 |
3 |
IMAGE_SUBSYSTEM_WINDOWS_CUI |
Windows控制台界面 |
5 |
IMAGE_SUBSYSTEM_OS2_CUI |
OS2控制台界面 |
7 |
IMAGE_SUBSYSTEM_POSIX_CUI |
POSIX控制台界面 |
8 |
IMAGE_SUBSYSTEM_NATIVE_WINDOWS |
不需要子系統 |
9 |
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI |
Windows CE圖形界面 |
● DataDirectory字段
這個字段可以說是最重要的字段之一,它由16個相同的IMAGE_DATA_DIRECTORY結構組成,雖然PE文件中的數據是按照裝入內存后的頁屬性歸類而被放在不同的節中的,但是這些處於各個節中的數據按照用途可以被分為導出表、導入表、資源、重定位表等數據塊,這16個IMAGE_DATA_DIRECTORY結構就是用來定義多種不同用途的數據塊的(如表17.4所示)。IMAGE_DATA_DIRECTORY結構的定義很簡單,它僅僅指出了某種數據塊的位置和長度。
IMAGE_DATA_DIRECTORY STRUCT
VirtualAddress DWORD ? ;數據的起始RVA
isize DWORD ? ;數據塊的長度
IMAGE_DATA_DIRECTORY ENDS
數據目錄列表的含義
索 引 |
索引值在Windows.inc中的預定義值 |
對應的數據塊 |
0 |
IMAGE_DIRECTORY_ENTRY_EXPORT |
導出表 |
1 |
IMAGE_DIRECTORY_ENTRY_IMPORT |
導入表 |
2 |
IMAGE_DIRECTORY_ENTRY_RESOURCE |
資源 |
3 |
IMAGE_DIRECTORY_ENTRY_EXCEPTION |
異常(具體資料不詳) |
4 |
IMAGE_DIRECTORY_ENTRY_SECURITY |
安全(具體資料不詳) |
5 |
IMAGE_DIRECTORY_ENTRY_BASERELOC |
重定位表 |
6 |
IMAGE_DIRECTORY_ENTRY_DEBUG |
調試信息 |
7 |
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE |
版權信息 |
8 |
IMAGE_DIRECTORY_ENTRY_GLOBALPTR |
具體資料不詳 |
9 |
IMAGE_DIRECTORY_ENTRY_TLS |
Thread Local Storage |
10 |
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG |
具體資料不詳 |
11 |
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT |
具體資料不詳 |
12 |
IMAGE_DIRECTORY_ENTRY_IAT |
導入函數地址表 |
13 |
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT |
具體資料不詳 |
14 |
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR |
具體資料不詳 |
15 |
未使用 |
在PE文件中尋找特定的數據時就是從這些IMAGE_DATA_DIRECTORY結構開始的,比如要存取資源,那么必須從第3個IMAGE_DATA_DIRECTORY結構(索引為2)中得到資源數據塊的大小和位置;同理,如果要查看PE文件導入了哪些DLL文件的哪些API函數,那就必須首先從第2個IMAGE_DATA_DIRECTORY結構得到導入表的位置和大小。