每个PE文件是以一个DOS程序开始的,有了它,一旦程序在DOS下执行,DOS就能识别出这是有效的执行体,然后运行紧随MZ header之后的DOS stub(DOS块)。DOS stub实际上是一个有效的EXE,在不支持PE文件格式的操作系统中,他将简单显示一个错误提示,类似于字符串“This program cannot be run in MS-DOS mode”。程序员也可以根据自己的意图实现完整的DOS代码。
PE文件头的第一个字节起始于一个传统的MS-DOS头部,被称作IMAGE_DOS_HEADER,大小为64B。
在IMAGE_DOS_HEADER和IMAGE_NT_HEADERS之间一个DOS Stub,这段程序用于在DOS环境中显示一个字符串,“This program cannot be run in DOS mode”,现在DOS早已灭绝,这段数据由编译器生成,可以用0填充或者删除(删除的话要移动很多数据)。
IMAGE_DOS_HEADER结构如下所示:
(注:左边的数字是到文件头的偏移量)
IMAGE_DOS_HEADER STRUCT
{
+00h WORD e_magic // Magic DOS signature MZ(4Dh 5Ah) DOS可执行文件标记+02h WORD e_cblp // Bytes on last page of file+04h WORD e_cp // Pages in file+06h WORD e_crlc // Relocations+08h WORD e_cparhdr // Size of header in paragraphs+0ah WORD e_minalloc // Minimun extra paragraphs needs+0ch WORD e_maxalloc // Maximun extra paragraphs needs+0eh WORD e_ss // intial(relative)SS value DOS代码的初始化堆栈SS+10h WORD e_sp // intial SP value DOS代码的初始化堆栈指针SP+12h WORD e_csum // Checksum+14h WORD e_ip // intial IP value DOS代码的初始化指令入口[指针IP]+16h WORD e_cs // intial(relative)CS value DOS代码的初始堆栈入口+18h WORD e_lfarlc // File Address of relocation table+1ah WORD e_ovno // Overlay number+1ch WORD e_res[4] // Reserved words+24h WORD e_oemid // OEM identifier(for e_oeminfo)+26h WORD e_oeminfo // OEM information;e_oemid specific+29h WORD e_res2[10] // Reserved words+3ch LONG e_lfanew // Offset to start of PE header 指向PE文件头
} IMAGE_DOS_HEADER ENDS
这里面有两个重要的数据成员。
- e_magic,这个必须为MZ,即0x5A4D(大小:2个字节)
- e_lfanew,这个成员的值为IMAGE_NT_HEADERS的偏移(大小:4个字节)