PE头由许多结构体组成,接下来分别解释一下各部分。

1.DOS头

微软最初创建PE格式的时候,DOS文件被人们广泛的使用,为了实现PE文件对DOS文件的兼容性。结果是在PE头的最前面添加了一个IMAGE_DOS_HEADER结构体,用来扩展已有的DOS EXE头。

//IMAGE_DOS_HEADER结构体
typedef strucet _IMAGE_DOS_HEADER{
WORD e_magic; //DOS signature : 4D5A ("MZ")
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[4];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[10];
LONG e_lfanew; //offset to NT header
} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;

IMAGE_DOS_HEADER结构体的大小为40个字节。该结构体有两个重要的”成员”:e_magic和e_lfanew.

  • e_magic : DOS签名(signature,4d5a=>ASCII值”MZ”)
  • e_lfanew : 指示NT头的偏移(根据不同文件拥有可变值)

所有的PE文件在开始部分(e_magic)都有DOS签名(“MZ”)。e_lfanew值指向NT头所在位置。(NT头的全称为IMAGE_NT_HEADERS)

PS: Mark Zbikowski在微软设计了DOS可执行文件,MZ即取自其名字的首字母。

使用010 Editor打开notepad.exe,查看IMAGE_DOS_HEADERS结构体,如图。

根据PE规范,文件开始的两个字节为4D5A,e_lfanew值为000000F0(intel的CPU以逆序储存数据,即小段序标识法)。


2.DOS存根

DOS存根(stub)在DOS头的下方,是个可选项,并且大小不固定(即有无DOS存根,文件均可正常运行)。DOS存根由代码与数混合而成,下图就是notepad.exe的DOS存根。

上图中,文件偏移40~4D区域为16位的汇编指令。32位windows OS中不会运行该命令(由于被识别为PE文件,所以完全忽视该代码)。在DOS环境中运行Notepad.exe文件,或者使用DOS调试器(debug.exe)运行他,可使其执行该代码(不识别PE文件格式,所以被识别为DOS EXE文件)。

界面中输出字符串”This program cannot be run in DOS mode”后便退出了,即notepad.exe文件虽然是32位的PE文件,但是带有MS-DOS兼容模式,可以在DOS环境中运行,执行DOS EXE代码,输出”This program cannot be run in DOS mode”后终止。根据该特性便可在一个可执行文件(EXE)中创建出另一个文件,使它在DOS与Windows中都能运行(在DOS环境中运行16位DOS代码,在Windows环境中运行32位Windows代码)。