PE文件是由许许多多的结构体组成的,程序在运行时就会通过这些结构快速定位到PE文件的各种资源,其结构大致如图所示,从上到下依次是Dos头、Nt头、节表、节区和调试信息(可选)。其中Dos头、Nt头和节表在本文中统称为PE文件头(因为SizeOfHeaders就是这三个头的总大小)、节区则称为节,所以也可以说PE文件是由PE文件头和节组成。
PE文件头保存着整个PE文件的索引信息,可以帮助PE装载器定位资源,而节则保存着整个PE文件的所有资源。正因为如此,所以存在着这样的说法:头是节的描述,节是头的具体化。
一:IMGAGE_DOS_HEADER
typedef struct _IMAE_DOS_HEADER {
WORD e_magic; **重要成员 相对该结构的偏移0x00**
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; **重要成员 相对该结构的偏移0x3C**
} IMAGE_DOS-HEADER, *PIMAGE_DOS_HEADER;
当我们用16进制编辑器打开一个PE文件时,就会发现所有PE文件的前两个字节都是MZ
,用十六进制表示是4D 5A
,这两个字母就是Mark Zbikowski
的姓名缩写,他是最初的MS-DOS设计者之一。如果把PE文件的这两个字节修改成其他数据,运行该PE文件就会无法正常运行(跳出黑窗口打印Program too big to fit in memory
然后闪退,有兴趣的朋友可以尝试下)。这里可以证明当PE文件运行时,首先就会检测这两个字节,如果不是MZ
则会退出运行。
在该结构体中另一个重要成员就是最后一个成员e_lfanew
。该成员的大小是LONG
类型4个字节。之所以说它重要是因为它保存着IMAGE_NT_HEADERS32
这个结构体在PE文件中的偏移地址,PE文件运行时只有通过该成员才能定位到PE签名(也就是IMAGE_NT_HEADERS32
结构体的起始位置)。
二:IMAGE_DOS_STUB (了解)
在IMAGE_DOS_HEADER
结构体后面紧跟着就是IMAGE_DOS_STUB
程序,它是运行在MS-DOS
下的可执行程序,当可执行文件运行于MS-DOS
下时,这个程序会打印This program cannot be run in DOS mode
这条消息。用户可以自己更改该程序,MS-DOS程序当前是可有可无的,如果你想使文件大小尽可能的小可以省掉MS-DOS程序,同时把前面的参数都清0。
三:IMAGE_NT_HEADERS32
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; **重要成员 PE签名 相