一、PE和PE32+文件格式
PE格式Windows所使用的32位的文件格式。PE32+则是64位Windows所使用的文件格式,在PE格式的基础上做了一些简单的修饰。PE32+格式较PE格式,没有新的结构出现,将以前的32位字段扩展成64位。在数据结构中,IMAGE_OPTIONAL_HEADER64较IMAGE_OPTIONAL_HEADER32,少了BaseOfData这个变量。以下简单的介绍以下PE32+格式,工具是我自己写的,用于显示PE32+的文件信息(工具是PE32+ Info View,演示的程序是64.exe)。
二、PE32+文件格式
PE32+文件格式跟PE格式的文件层次结构一样,包含MS-DOS头部和PE32+文件头。描述PE格式的文件主要存在于winnt.h。以后的数据结构说明主要从winnt.h文件截取出来。
(一)MS-DOS头部
PE32+也不例外,也是以一个DOS程序开始的。当程序在DOS下执行时,DOS就能识别出这是有效的执行体,并且运行紧跟在MZ头部的DOS块(即DOS stub)。DOS块是一个有效的的EXE,在不支持PE文件格式的操作系统中,它将简单地显示一个错误提示,类似于字符串“This program cannot be run in MS-DOS mode”。我们可以根据自己的需要去实现完整的DOS代码。但通常情况下,这部分代码由编译器自动生成。我们把DOS MZ头与DOS块合成DOS文件头。
PE32+的第一个字节也起始于一个传统的MS-DOS头部,即IMAGE_DOS_HEADER。其数据结构如下:
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number,DOS可执行文件标记“MZ”
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,DOS代码入口地址IP
WORD e_cs; // Initial (relative) CS value,DOS代码入口CS
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,指向PE文件“PE”
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
(二)PE32+文件头
紧跟着DOS stub的是PE32+文件头。PE32+文件头是PE相关结构NT映像头(IMAGE_NT_HEADERS)的简称,包含许多PE装载器要用到的重要字段。执行体在支持PE32+文件结构的操作系统中,PE装载器首先从IMAGE_DOS_HEADER结构中的e_lfanew字段里找到PE32+ Header的起始偏移量,加上基址即可得到PE32+文件头。
IMAGE_NT_HEADERS64(还有一个是为32位的可执行文件准备得,即IMAGE_NT_HEADERS32,这两个结构几乎没有区别)由三个字段组成:
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature; //PE文件标识,"PE00"
IMAGE_FILE_HEADER FileHeader; //PE映像文件头,包含PE文件的一些基本信息
IMAGE_OPTIONAL_HEADER64 OptionalHeader; //PE可选映像头,定义了更多的数据
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
1.Sinature字段
在一个有效的PE32+文件里,Signature字段被置为00004550h,对应的ASCII码为“PE00”,#define IMAGE_NT_SIGNATURE定义了这个值。
define IMAGE_NT_SIGNATURE 0x00004550 // PE00
注:DOS头部的e_lfanew字段指向了“PE00”。
2.IMAGE_FILE_HEADER结构
PE32+的IMAGE_FILE_HEADER结构和PE文件中的结构是一样的,其包含了PE文件的一些基本信息,最重要的一个域指出了IMAGE_OPTIONAL_HEADER64的大小。
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; //运行平台
WORD NumberOfSections; //文件的区块数目
DWORD TimeDateStamp; //文件创建日期和时间
DWORD PointerToSymbolTable; //指向符号表(用于调试)
DWORD NumberOfSymbols; //符号表中符号个数(用于调试)
WORD SizeOfOptionalHeader; //IMAGE_OPTIONAL_HEADER64的大小
WORD Characteristics; //文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
注:每个域的具体意义就不在此说明了,具体的可以参考相关PE文件的书籍或者资料。
3.IMAGE_OPTIONAL_HEADER64
IMAGE_OPTIONAL_HEADER64(可选映像头)是一个可选的结构,但由于IMAGE_FILE_HEADER结构不足以定义PE文件属性,因此可选映像头中定义了更多的数据,两者连起来就是一个完整的“PE32+头结构”。
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic; //一个标记字,PE文件为010B,PE32+为020B
BYTE MajorLinkerVersion; //链接程序的主版本号
BYTE MinorLinkerVersion; //链接程序的此版本号
DWORD SizeOfCode; //所有带有IMAGE_SCN_CNT_CODE属性区块的总共大小
DWORD SizeOfInitializedData; //已初始化数据块的大小
DWORD SizeOfUninitializedData; //未初始化数据块的大小
DWORD AddressOfEntryPoint; //程序执行入口RVA
DWORD BaseOfCode; //代码段的起始RVA
ULONGLONG ImageBase; //代码段的起始RVA
DWORD SectionAlignment; //当被装入内存的区块对齐大小
DWORD FileAlignment; //磁盘上PE文件内的区块对齐大小
WORD MajorOperatingSystemVersion; //操作系统的主版本号
WORD MinorOperatingSystemVersion; //操作系统的此版本号
WORD MajorImageVersion; //该可执行文件的主版本号,由用户自定义
WORD MinorImageVersion; //该可执行文件的次版本号,由用户自定义
WORD MajorSubsystemVersion; //所需子系统主版本号
WORD MinorSubsystemVersion; //所需子系统次版本号
DWORD Win32VersionValue; //通常被设置为0,从不用的字段
DWORD SizeOfImage; //映像装入内存后的大小
DWORD SizeOfHeaders; //MS-DOS头部,PE头部和区块表的组合尺寸
DWORD CheckSum; //映像的检验和。
WORD Subsystem; //一个表明可执行文件所期望的子系统
WORD DllCharacteristics; //DllMain()函数何时被调用,默认为0.
ULONGLONG SizeOfStackReserve; //初始化堆栈大小
ULONGLONG SizeOfStackCommit; //初始化实际提交堆栈大小
ULONGLONG SizeOfHeapReserve; //初始化保留栈的大小,默认值是1MB。
ULONGLONG SizeOfHeapCommit; //初始化实际保留栈的大小。默认值为4KB
DWORD LoaderFlags; //与调试相关,默认值为0
DWORD NumberOfRvaAndSizes; //数据目录的项数,这个字段一般是16.
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];数据目录表
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
数据目录表IMAGE_DATA_DIRECTORY的结构定义如下:
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress; //数据块的起始RVA
DWORD Size; //数据块的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
数据目录表成员包括输出表(Export Table)、输入表(Import Table)等数据,具体的各项成员如下:
Export Table IMAGE_DIRECTORY_ENTRY_EXPORT // Export Directory,输出表
Import Tbale IMAGE_DIRECTORY_ENTRY_IMPORT // Import Directory,输入表
Resource Table IMAGE_DIRECTORY_ENTRY_RESOURCE // Resource Directory,资源
Exception Table IMAGE_DIRECTORY_ENTRY_EXCEPTION // Exception Directory,异常
Security Table IMAGE_DIRECTORY_ENTRY_SECURITY // Security Directory,安全
Base relocation Table IMAGE_DIRECTORY_ENTRY_BASERELOC // Base Relocation Table,重定位表
Debug IMAGE_DIRECTORY_ENTRY_DEBUG // Debug Directory,调试信息
Architecture IMAGE_DIRECTORY_ENTRY_ARCHITECTURE // Architecture Specific Data,版权信息
Global Ptr IMAGE_DIRECTORY_ENTRY_GLOBALPTR // RVA of GP
Thread local storage(TLS) IMAGE_DIRECTORY_ENTRY_TLS // TLS Directory
Load configuration IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG // Load Configuration Directory
Bound Import IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT // Bound Import Directory in headers
Import Address Table(IAT) IMAGE_DIRECTORY_ENTRY_IAT // Import Address Table
Delay Import IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT // Delay Load Import Descriptors
COM Descriptor IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR // COM Runtime descriptor
Reserved //一般情况为0
4.区块表
在PE32+文件头与原始数据之间存在一个区块表,区块表包含每个块在映像中的信息,分别指向不同的区块实体。区块表是一个IMAGE_SECTION_HEADER结构数组,其数目由IMAGE_NT_HEADER64.NumberOfSections决定。
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文件使用,重定位的偏移
DWROD PointerToLinenumbers; //符号表的偏移(供调试用)
WORD NumberOfRelocations; //在OBJ文件中使用,重定位项数目
WORD NumberOfLinenumbers; //行号表中的行号的数目
DWORD Characteristics; //区块的属性值
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
以下附上工具和演示文件:
[课程]FART 脱壳王!加量不加价!FART作者讲授!
上传的附件: