PE文件头介绍


32位PE结构

DOS MZ头

因为以e_magic开头。所对应的是4D 5A,对应ANSI是MZ,纪念Mark Zbikowski

+0h WORD e_magic // Magic DOS signature MZ(4Dh 5Ah) DOS可执行文件标记
+2h WORD e_cblp // Bytes on last page of file最后页中的字节数
+4h WORD e_cp // Pages in file文化中的全部和部分页数
+6h WORD e_crlc // Relocations重定位表中的指针数
+8h 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)OEM标识符
+26h WORD e_oeminfo // OEM information;e_oemid specificOEM信息
+29h WORD e_res2[10] // Reserved words保留字
+3ch DWORD e_lfanew // Offset to start of PE header PE头相对于文件的偏移地址

DOS Stub

16位系统需要

删除不影响系统识别与运行

 

PE头绝对位置计算

PE_Start=DOS MZ基地址+IMAGE_DOS_HEADER.elfanew

PE头标识signature

PE头标识signature=50 45 00 00 ANSI为PE\0\0

标准PE头IMAGE_FILE_HEADER

typedef struct _IMAGE_FILE_HEADER {

WORD Machine;//运行平台

WORD NumberOfSections;//PE中节的数量

DWORD TimeDateStamp;//文件创建日期和时间

DWORD PointerToSymbolTable;//指向符号表

DWORD NumberOfSymbols;符号表中的符号数量

WORD SizeOfOptionalHeader;扩展头结构的长度

WORD Characteristics;//文件属性

} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

详细解析

Machine指明PE文件支持的CPU类型,0x014c表明是Intel i386的CPU

NumberOfSections指明PE文件包含的节区数量,0x0004表明有4块

TimeDateStamp字段指明文件的创建时间,为1970年1月1日以来用格林威治时间计算的秒数

SizeOfOptionalHeader字段,指明在IMAGE_NT_HEADERS中紧跟在FileHeader后的OptionalHeader的大小,对于32位的PE文件而言,这个值的大小通常为0x00E0;
Characteristics字段,表明文件的属性。如果Characteristics & 0x2000 = 0x2000,那么表明这是一个DLL文件

扩展PE头IMAGE_OPTIONAL_HEADER32

typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;//魔术字107h=ROM Inage,10Bh=exe Image
BYTE MajorLinkerVersion;//链接器版本号
BYTE MinorLinkerVersion;
DWORD SizeOfCode;//所有含代码的节的总大小
DWORD SizeOfInitializedData;//所有含已初始化数据的节的总大小
DWORD SizeOfUninitializedData;//所有含未初始化数据的节的大小
DWORD AddressOfEntryPoint;//程序执行入口RVA
DWORD BaseOfCode;//代码的节的起始RVA
DWORD BaseOfData;//数据的节的起始RVA
DWORD ImageBase;程序的建议装载地址
DWORD SectionAlignment;//内存中的节的对齐粒度
DWORD FileAlignment;文件中的节的对齐粒度
WORD MajorOperatingSystemVersion;操作系统版本号
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;//该PE的版本号
WORD MinorImageVersion;
WORD MajorSubsystemVersion;//所需子系统的版本号
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;//未用
DWORD SizeOfImage;//内存中的真个PE映像大小
DWORD SizeOfHeaders;//所有头+节表的大小
DWORD CheckSum;效验和
WORD Subsystem;//文件的子系统
WORD DllCharacteristics;//DLL文件特征
DWORD SizeOfStackReserve;//初始化时的栈大小
DWORD SizeOfStackCommit;//初始化时实际提交的栈大小
DWORD SizeOfHeapReserve;//初始化时保留的堆大小
DWORD SizeOfHeapCommit;//初始化时实际提交的堆大小
DWORD LoaderFlags;//与调试有关
DWORD NumberOfRvaAndSizes;//下面的数据目录结构的项目数量
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];//数据目录
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

Magic,表明是ROM映像还是普通的可执行映像,普通的可执行文件的值为0x010B,PE32+可执行文件的值为0x020B(PE32+即64位的PE文件,这种文件只能运行在64位的Windows操作系统下)(0xd0-0xd1)

SizeOfCode,代码区块的大小,通常而言可执行文件仅有一个代码区块.text,所以通常就是.text区块的大小(磁盘对齐);(0xd4-0xd7)

AddressOfEntryPoint,重要字段,程序执行的入口点地址,是一个RVA值;(0xe0-0xe3)

BaseOfCode,代码段的起始地址,是一个RVA值,通常而言就是.text区块的起始RVA;(0xe4-0xe7)

BaseOfData,数据段的起始地址,是一个RVA值,通常而言就是.data区块的起始RVA;(0xe8-0xeb)

ImageBase,重要字段,PE文件在内存中首选的装载基地址,文件真实装载地址位于ImageBase+AddressOfEntryPoint;(0xec-0xef)

SectionAlignment,当PE文件装载到内存时区块的对齐大小,假设.text区块的大小为0x7748,而SectionAlignment的大小为0x1000,那么对齐后的大小为0x8000字节;(0xf0-0xf3)

FileAlignment,磁盘上PE文件中区块的对齐大小,对齐方式类似SectionAlignment;(0xf4-0xf7)

SizeOfImage,PE文件被装载到内存空间后总的大小,指从ImageBase到最后一个区块的大小(内存中开头+几个段在内存中的大小,是SectionAlignment的倍数);(0x108-0x10b)

SizeOfHeaders,Dos头、DosStub、PE头以及区块头的总大小,并进行FileAlignment对齐后的大小(exe文件中程序正式开始的地方,为FileAlignment的倍数)(0x10c-0x10f);

NumberOfRvaAndSizes,数据目录项的个数,固定为16,即后面一个成员DataDirectory的数组元素个数;(0x12c-0x12f)

DataDirectory,数据目录表,包含有输入表、输出表等表项的具体信息;

PE头IMAGE_NT_HEADERS

typedef struct _IMAGE_NT_HEADERS {

DWORD Signature;//PE头标识

IMAGE_FILE_HEADER FileHeader;//标准PE头

IMAGE_OPTIONAL_HEADER32 OptionalHeader;//拓展PE头

} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

数据目录项IMAGE_DATA_DIRECTORY

typedef struct _IMAGE_DATA_DIRECTORY {

DWORD VirtualAddress;//数据的起始RVA

DWORD Size;//数据块的长度

} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

DataDirectory是一个数据目录表数组,数组的元素个数为16,各元素对应表项如下

 

节表项_IMAGE_SECTION_HEADER

typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];//8个字节节名
union {
DWORD PhysicalAddress;
DWORD VirtualSize;//节区的尺寸
} Misc;
DWORD VirtualAddress;//节区的RVA地址
DWORD SizeOfRawData;//在文件中对齐后的尺寸
DWORD PointerToRawData;//在文件中的偏移
DWORD PointerToRelocations;//在OBJ文件中的使用
DWORD PointerToLinenumbers;//行号表的位置(供调试用)
WORD NumberOfRelocations;//在OBJ文件中的使用
WORD NumberOfLinenumbers;//行号表中行号的数量
DWORD Characteristics;//节的属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER

Name,为对应节区的名字,其中IMAGE_SIZEOF_SHORT_NAME的值固定为8。如果名字的长度小于8,则以NULL字符结束;如果名字的长度等于8,则没有NULL字符,因为数组长度为8。节区的名字通常以点号开头,如.text、.data等,通常而言,这个名字可以随便修改。

VirtualSize,在未对齐的情况下,区块所有数据的大小。

VirtualAddress,区块被装载到内存时的RVA,这个值总是SectionAlignment的整数倍。

SizeOfRawData,区块数据在磁盘文件中按照FileAlignment对齐后的大小。

PointerToRawData,区块数据在磁盘文件中的偏移地址。

PointerToRelocations、PointerToLinenumbers、NumberOfRelocations、NumberOfLinenumbers:不是很重要的字段,这里不作研究。

Characteristics,区块的属性值,表明区块的可读、可写、可执行等相关属性。


以上是整个PE文件头结构的大致构成

具体的不展开写了,要么篇幅过长。具体的数据结构解析请自行百度。

发表评论

邮箱地址不会被公开。 必填项已用*标注