所谓PE文件就是可执行文件在硬盘中存储是的文件表示,Windows中可执行文件的文件表示的发展途径为com->LE(Linerar executable)->PE(Portable Executable File Formate)。在程序运行的时候PE文件中的部分内容被载入内存(各种节),这些内容提供了程序运行所需的所有信息,下图展示了PE文件到内存的映射:
PE文件结构
下图展示了PE文件的总体结构,在下面小节中将对各个结构进行详细的说明。
IMAGE_DOS_HEADER
DOS部分是为了兼容DOS系统程序,此部分包括Header和stub两部分,前者是对DOS程序的描述,后者包含了DOS可执行程序,Header头部如下所示:
IMAGE_DOS_HEADER STRUCT
e_magic WORD ;DOS可执行文件标记
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 ;DOS代码段偏移指针
e_cs WORD ;DOS代码段基址
e_lfarlc WORD
e_ovno WORD ;DOS文件头部到此为此,下述字段为了对其他可执行文件进行扩充,DOS系统对下述字段不解释
e_res WORD
e_oemid WORD
e_oeminfo WORD
e_res2 WORD
e_lfanew DWORD ;指向PE文件头部(或者LE,LX其他可执行文件头部)
IMAGE_DOS_HEADER ENDS
通过Lord PE工具可以查看程序的IMAGE_DOS_HEADER信息:
DOM可执行文件的识别标志为MZ
DOS Stub
DOS系统下可执行的代码,默认情况下这段代码只会简单的显示一个“This program cannot be run in DOS mode”然后就退出了,具体代码如下图黄框所示(Study PE工具截图)
上述黄框中部分机器码内容如下:
0E PUSH cs
1F POP ds
BA0E00 MOV dx, 0x000E ;串地址(即This program cannot.....的地址)
B409 MOV ah, 0x09 ;显示字符串
CD21 INT 0x21 ;中断调用
B8014C MOV ax,0x4c01 ;带返回码结束,返回码为1
CD21 INT 0x21
可以使用链接器(link.exe)的/stud参数在链接时指定其他的DOM程序来代替上述提示程序
IMAGE_NT_HEADERS
IMAGE_NT_HEADERS是正式的PE文件头,本部分以8字节为单位对其,详细结构如下所示:
IMAGE_NT_HEADERS STRUCT
Signature DWORD ;PE文件标识
FileHeader IMAGE_FILE_HEADER
OptionalHeader IMAGE_OPTIONAL_HEADER32
IMAGE_NT_HEADERS ENDS
其中Signature的值为0x00004550也就是PE\0\0
IMAGE_FILE_HEADER
IMAGE_FILE_HEADER STRUCT
Machine WORD ;运行平台
NumberOfSections WORD ;文件的节数
TimeDateStamp DWORD ;文件创建日期和时间
PointerToSymbolTable DWORD ;符号表指针(调试用)
NumberOfSymbols DWORD ;符号表中的符号数量(调试用)
SizeOfOptionalHeader WORD ;IMAGE_OPTIONAN_HEADER32结构的长度
Characteristics WORD ;文件属性
IMAGE_FILE_HEADER ENDS
下图是Lord PE软件载入某执行文件后上述结构体的值:
- Machine:表示运行平台
- TimeDateStamp:自1969年12月31日下午4点到文件创建时的秒数
- SizeOfOptionalHeader:这个值为00e0h
- Characteristics:这个字段16位(WORD),每一位描述着不同的文件属性
IMAGE_OPTIONAL_HEADER32
此结构体本意是让开发者能够在PE文件头中使用自定义数据,这个结构体弥补了IMAGE_FILE_HEADER不能够充分描述PE文件属性的不足
IMAGE_OPTIONAL_HEADER32 STRUCT:
Magic WORD ;
MajorLinkerVersion BYTE ;连接器版本号
MinorLinkerVersion BYTE ;
SizeOfCode DWORD ;所有包含代码的节的总大小
SizeOfInitializedData DWORD ;所有包含已初始化数据的节的总大小
SizeOfUninitializedData DWORD ;所有包含未初始化数据的节的总大小
AddressOfEntryPoint DWORD ;程序执行的入口偏移虚拟地址(RVA)
BaseOfCode DWORD ;代码节的起始偏移虚拟地址(RVA)
BaseOfData DWORD