重读PE文件格式
感觉很有必要重新研究PE格式,所以重读了PE格式的相关文档,心得如下:
1.对于DOS头,其定义如下:

typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
因为我们开发的是windows下的程序,所以重要的字段有两个,一个是e_magic字段,一个是e_lfanew,e_magic字段始终为5A4D,即ASCII字符的MZ,e_lfanew保存的是PE文件头在文件中的偏移量,我想作为exe程序的装载器,首先检查DOS头的e_magic字段是否为MZ,然后读取e_lfanew字段的值,以此找到PE文件头
2.找到PE文件头,PE文件头的定义如下:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
signature字段同DOS头的e_magic一样,是个标志字段,其值始终为4550,IMAGE_FILE_HEADER结构定义如下:

typedef struct _IMAGE_FILE_HEADER {
WORD Machine;//运行平台
WORD NumberOfSections;//文件的节数目
DWORD TimeDateStamp;//文件创建日期和时间
DWORD PointerToSymbolTable;//指向符号表(用于调试)
DWORD NumberOfSymbols;//符号表中的符号数量(用于调试)
WORD SizeOfOptionalHeader;//IMAGE_OPTIONAL_HEADER32结构的长度
WORD Characteristics;//文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
WORD Machine;//运行平台
WORD NumberOfSections;//文件的节数目
DWORD TimeDateStamp;//文件创建日期和时间
DWORD PointerToSymbolTable;//指向符号表(用于调试)
DWORD NumberOfSymbols;//符号表中的符号数量(用于调试)
WORD SizeOfOptionalHeader;//IMAGE_OPTIONAL_HEADER32结构的长度
WORD Characteristics;//文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
machine字段表示当前文件应该运行的平台,对于PC来说,此值应该为14C
NumberOfSections这个字段表示文件的节的数目,这个值很重要,我试着把一个文件的这个字段加1,然后发现文件不能正常装载了,因此系统应该是据此字段来装载PE文件的节的
Characteristics指明了当前PE文件是什么类型的,如果是exe,则值为10F,如果是DLL,则为210E
IMAGE_OPTIONAL_HEADER32是非常重要的一个结构,他里面有很多重要的信息,定义如下:

typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;//10Bh=exe Image
BYTE MajorLinkerVersion;//链接器版本号
BYTE MinorLinkerVersion;
DWORD SizeOfCode;//所有含代码的节的总大小
DWORD SizeOfInitializedData;//所有含已初始化数据的节的总大小
DWORD SizeOfUninitializedData;//所有含未初始化数据的节的大小
DWORD AddressOfEntryPoint;//程序执行入口RVA
DWORD BaseOfCode;//代码的节的起始RVA
DWORD BaseOfData;//数据的节的起始RVA
//
// NT additional fields.
//
DWORD ImageBase;//程序的建议装载地址
DWORD SectionAlignment;//内存中的节的对齐粒度
DWORD FileAlignment;//文件中的节的对齐粒度
WORD MajorOperatingSystemVersion;//操作系统主版本号
WORD MinorOperatingSystemVersion;//操作系统副版本号
WORD MajorImageVersion;//可运行于操作系统的最小版本号
WORD MinorImageVersion;//
WORD MajorSubsystemVersion;//可运行于操作系统的最小子版本号
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;//内存中整个PE映像尺寸
DWORD SizeOfHeaders;//所有头+节表的大小
DWORD CheckSum;//
WORD Subsystem;//文件的子系统
WORD DllCharacteristics;//
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;
//
// Standard fields.
//
WORD Magic;//10Bh=exe Image
BYTE MajorLinkerVersion;//链接器版本号
BYTE MinorLinkerVersion;
DWORD SizeOfCode;//所有含代码的节的总大小
DWORD SizeOfInitializedData;//所有含已初始化数据的节的总大小
DWORD SizeOfUninitializedData;//所有含未初始化数据的节的大小
DWORD AddressOfEntryPoint;//程序执行入口RVA
DWORD BaseOfCode;//代码的节的起始RVA
DWORD BaseOfData;//数据的节的起始RVA
//
// NT additional fields.
//
DWORD ImageBase;//程序的建议装载地址
DWORD SectionAlignment;//内存中的节的对齐粒度
DWORD FileAlignment;//文件中的节的对齐粒度
WORD MajorOperatingSystemVersion;//操作系统主版本号
WORD MinorOperatingSystemVersion;//操作系统副版本号
WORD MajorImageVersion;//可运行于操作系统的最小版本号
WORD MinorImageVersion;//
WORD MajorSubsystemVersion;//可运行于操作系统的最小子版本号
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;//内存中整个PE映像尺寸
DWORD SizeOfHeaders;//所有头+节表的大小
DWORD CheckSum;//
WORD Subsystem;//文件的子系统
WORD DllCharacteristics;//
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;
以上是简单的注释,详细解释放在下一篇文章,下午来写