PE文件头属性
PE文件头:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader; //这里枚举的是32位的,还有64位的,所以有两种结构体
}
分为三部分:
1、PE文件头标识 2、PE文件表头 3、可扩展文件表头
1、PE文件头标识:
没啥好讲的,就4个字节,但是不能修改,作为标识使用!
2、标准文件头:占20个字节,是一个_IMAGE_FILE_HEADER
结构体
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; //可以运行在什么样的CPU上,如果是 x64的 那么字节则显示8664
WORD NumberOfSections; //表示节的数量
DWORD TimeDateStamp; // 编译的时候,编译器填写的当前时间戳
DWORD PointerToSymbolTable; //调试相关
DWORD NumberOfSymbols; //调试相关
WORD SizeOfOptionalHeader; // PE拓展头的大小,32位的默认为E0h,64位的默认为F0h,大小可以自定义
WORD Characteristics; // 文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
关于该结构体中的Characteristics
成员的每个位上的代表含义如下:
3、可扩展文件表头:在x64系统中占0xF0大小,在x32系统中占0xE0大小
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic; // 分辨32位程序还是64位,如果32位则10B,64位则20B
BYTE MajorLinkerVersion; //链接器版本号
BYTE MinorLinkerVersion; //链接器版本号
DWORD SizeOfCode; //所有代码节的总和 文件对齐后的大小 编译器填写的,无用处
DWORD SizeOfInitializedData; //已经初始化数据的节的总大小 文件对齐后的大小 编译器填写的,无用处
DWORD SizeOfUninitializedData; // 未初始化数据的节的总大小 文件对齐后的大小 编译器填写的,无用处
DWORD AddressOfEntryPoint; // 程序入口
DWORD BaseOfCode; //代码开始的基址 编译器填写的,无用处
DWORD BaseOfData; //数据开始的基址 编译器填写的,无用处
//
// NT additional fields.
//
DWORD ImageBase; //内存镜像基址
DWORD SectionAlignment; //内存对齐
DWORD FileAlignment; //文件对齐
WORD MajorOperatingSystemVersion; //操作系统版本号
WORD MinorOperatingSystemVersion; //操作系统版本号
WORD MajorImageVersion; //PE文件自身的版本号
WORD MinorImageVersion; //PE文件自身的版本号
WORD MajorSubsystemVersion; //运行所需要子系统的版本号
WORD MinorSubsystemVersion; //运行所需要子系统的版本号
DWORD Win32VersionValue; //子系统版本的值,必须为0
DWORD SizeOfImage; //内存中整个PE文件的映射尺寸,比实际的值大,必须是SectionAlignment整数倍
DWORD SizeOfHeaders; //所有的头+节表按照文件对齐后的大小
DWORD CheckSum; //校验和,可伪造
WORD Subsystem; //子系统, 驱动程序(1) 图形界面(2) DLL(3)
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;
1、ImageBase
决定程序在内存中的什么地方开始加载
2、当程序在内存中运行的时候,真正的入口点地址为AddressOfEntryPoint + ImageBase
的地方
3、SizeOfImage
比实际的值大是什么意思呢?假如在内存中拉伸过后的大小为0x5000,该值还需要是内存对齐大小(SectionAlignment)整数倍,所以在内存中的大小就可以是0x6000
4、SizeOfHeaders
大小是 DOS头 + PE标识 + PE标准头 + PE可选扩展头 + 节表 的总和,再按文件对齐大小(FileAlignment)对齐的,举个例子,如果DOS头 + PE标识 + PE标准头 + PE可选扩展头 + 节表 的总和是0x1800,假如文件对齐大小是0x200,那么SizeOfHeaders
也就是0x2000,那么多出来的0x200其实就是空数据!