PE : portable execute (windows下的可执行文件)
VA : 进程虚拟内存的绝对地址,方位是 0x00000000 ~ 0xFFFFFFFF (进程的虚拟内存是4G)
RVA : 相对的虚拟地址,从某个基准位置(images)开始的相对地址
PE分为如下部分 :
PE头 : 从DOS头(DOS Header) 到节区头(section header)
dos头、dos存根、NT头
PE体 : 代码(.text) 数据(.data) 资源(.rsrc)
关键结构体 :
********************************* PE头相关 *********************************
DOS头, 40字节
typedef struct _IMAE_DOS_HEADER { //DOS .EXE header 位置
WORD
e_magic; //Magic number; 0x00 AD5A
WORD e_cblp; //Bytes on last page of file 0x02
WORD e_cp; //Pages in file 0x04
WORD e_crlc; //Relocations 0x06
WORD e_cparhdr; //Size of header in paragraphs 0x08
WORD e_minalloc; //Minimum extra paragraphs needed 0x0A
WORD e_maxalloc; //Maximum extra paragraphs needed 0x0C
WORD e_ss; //Initial (relative) SS value 0x0E
WORD e_sp; //Initial SP value 0x10
WORD e_csum; //Checksum 0x12
WORD e_ip; //Initial IP value 0x14
WORD e_cs; //Initial (relative) CS value 0x16
WORD e_lfarlc; //File address of relocation table 0x18
WORD e_ovno; //Overlay number 0x1A
WORD e_res[4]; //Reserved words 0x1C
WORD e_oemid; //OEM identifier (for e_oeminfo) 0x24
WORD e_oeminfo; //OEM information; e_oemid specific 0x26
WORD e_res2[10]; //Reserved words 0x28
LONG e_lfanew; /File address of new exe header 0x3C 如下图可知, 值为0x000000F8
} IMAGE_DOS-HEADER, *PIMAGE_DOS_HEADER;
使用Hex Edit工具可以查看 :
https://pan.baidu.com/s/1zaP2Hl5h7IrWMGGdG7HFMQ
DOS存根 :
在dos头的下方,可有可无,由代码和数据混合组成, 没有也可以正常运行。
从下图可知,e_lfanew的位置为0x3四个字节, 值为0x000000F8, 所有dos存根的内容为 0x00000040 ~ 0x000000F8 (.. this is program cannot be run in DOS mode ....)
备注 : 后续部分小截图直接从这里截图的
NT头
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; //位置在e_lfanew上 PE signature : 5045
IMAGE_FILE_HEADER FileHeader; //e_lfanew + 0x4 文件头结构体
IMAGE_OPTIONAL_HEADER32 OptionalHeader; //e_lfanew + 0x18 可选头结构体
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
NT头 : 文件头
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; //位置为 e_lfanew + 0x4 //该字段表示可执行文件的目标CPU类型 014c intel
WORD NumberOfSections; //e_lfanew + 0x6 //该字段表示PE文件的节区的个数 0004
DWORD TimeDateStamp; //e_lfanew + 0x8 //该字段表明文件时何时被创建的,这个值是自1970年1月1日以来用格林
//威治时间计算的秒数
DWORD PointerToSymbolTable; //e_lfanew + 0xC //
DWORD NumberOfSymbols; //e_lfanew + 0x10 //
WORD SizeOfOptionalHeader; //e_lfanew + 0x12 //该字段指定IMAGE_OPTIONAL_HEADER结构的大小
WORD Characteristics; //e_lfanew + 0x14 //该字段指定文件的类型
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; //大小20字节
Machine字段取值
宏定义 值 意义
#define IMAGE_FILE_MACHINE_I386 0x014c Intel
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 DEC Alpha
#define IMAGE_FILE_MACHINE_IA64 0x0200 Intel(64 - bit)
#define IMAGE_FILE_MACHINE_AXP64 0x0284 DEC Alpha(64 - bit)
Characteristics字段取值
宏定义 值 意义
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 文件中不存在重定位信息
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 文件可执行
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 行号信息已从文件中移除
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 符号信息已从文件中移除
#define IMAGE_FILE_DLL 0x2000 DLL文件
#define IMAGE_FILE_SYSTEM 0x1000 系统文件
#define IMAGE_FILE_32BIT_MACHINE 0x0100 目标平台为32位平台
NT头 : 可选头
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic
; //位置为 e_lfanew + 0x18 //文件的状态类型 10B(32位) 20B(64位)
BYTE MajorLinkerVersion; //e_lfanew + 0x1A //主链接版本号
BYTE MinorLinkerVersion; //e_lfanew + 0x1B //次链接版本号
DWORD SizeOfCode; //e_lfanew + 0x1C //代码节的大小
DWORD SizeOfInitializedData; //e_lfanew + 0x20 //已初始化数据块的大小
DWORD SizeOfUninitializedData; //e_lfanew + 0x24 //未初始化数据块的大小
DWORD AddressOfEntryPoint
; //e_lfanew + 0x28 //程序执行的入口,相对虚拟地址,简称EP
DWORD BaseOfCode; //e_lfanew + 0x2C //代码段的起始相对虚拟地址
DWORD BaseOfData; //e_lfanew + 0x30 //数据段的起始相对虚拟地址
DWORD ImageBase; //e_lfanew + 0x34 //内存首选装载地址
DWORD SectionAlignment //e_lfanew + 0x38 //节在内存中的对齐值
DWORD FileAlignment //e_lfanew + 0x3C //节在文件中的对齐值
WORD MajorOperatingSystemVersion; //e_lfanew + 0x40 //要求最低操作系统的主版本号
WORD MinorOperatingSystemVersion; //e_lfanew + 0x42 //要求最低操作系统的次版本号
WORD MajorImageVersion; //e_lfanew + 0x44 //可执行文件的主版本号
WORD MinorImageVersion; //e_lfanew + 0x46 //可执行文件的次版本号
WORD MajorSubsystemVersion; //e_lfanew + 0x48 //要求最低子系统的主版本号
WORD MinorSubsystemVersion; //e_lfanew + 0x4A //要求最低子系统的次版本号
DWORD Win32VersionValue; //e_lfanew + 0x4C //该成员变量是被保留的
DWORD SizeOfImage; //e_lfanew + 0x50 //可执行文件装入内存后的总大小
DWORD SizeOfHeader; //e_lfanew + 0x54 //PE头的大小,包括DOS头、PE头、节表的总和大小
DWORD CheckSum; //e_lfanew + 0x58 //校验和
WORD Subsystem; //e_lfanew + 0x5C //可执行文件的子系统类型
WORD DllCharacteristics; //e_lfanew + 0x5E //指定DLL文件的属性,该值大部分时候为0
DWORD SizeOfStackReserve; //e_lfanew + 0x60 //为线程保留的栈大小
DWORD SizeOfStackCommit; //e_lfanew + 0x64 //为线程已经提交的栈大小
DWORD SizeOfHeapReserve; //e_lfanew + 0x68 //为线程保留的堆大小
DWORD SizeOfHeapCommit; //e_lfanew + 0x6C //为线程已经提交的堆大小
DWORD LoaderFlags; //e_lfanew + 0x70 //被废弃的成员值
DWORD NumberOfRvaandSizes; //e_lfanew + 0x74 //数据目录项的个数
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; //e_lfanew + 0x78 //数据目录表
//#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; //大小224字节
Magic取值
宏定义 值 意义
#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b 可执行文件
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 ROM文件
Subsystem取值
宏定义 值 意义
#define IMAGE_SUBSYSTEM_UNKNOWN 0 未知子系统
#define IMAGE_SUBSYSTEM_NATIVE 1 不需要子系统
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 图形子系统
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 控制台子系统
//IMAGE_DATA_DIRECTORY
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
DataDirectory
索引 宏定义 意义
0 IMAGE_DIRECTORY_ENTRY_EXPORT 导出表
1 IMAGE_DIRECTORY_ENTRY_IMPORT 导入表
2 IMAGE_DIRECTORY_ENTRY_RESOURCE 资源
3 IMAGE_DIRECTORY_ENTRY_EXCEPTION 异常(具体资料不详)
4 IMAGE_DIRECTORY_ENTRY_SECURITY 安全(具体资料不详)
5 IMAGE_DIRECTORY_ENTRY_BASERELOC 重定位表
6 IMAGE_DIRECTORY_ENTRY_DEBUG 调试信息
7 IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 版权信息
8 IMAGE_DIRECTORY_ENTRY_GLOBALPTR 具体资料不详
9 IMAGE_DIRECTORY_ENTRY_TLS Thread Local Storage
10 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 具体资料不详
11 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 具体资料不详
12 IMAGE_DIRECTORY_ENTRY_IAT 导入函数地址表
13 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 具体资料不详
14 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 具体资料不详
15 未使用
节区头 :
typedef struct _IMAGE_SECTION_HEADER { //第一个节区,每个节区依次往后推40字节即可
BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //位置为 e_lfanew + 0xF8 //保存节的名称
union {
DWORD PhysicalAddress; //e_lfanew + 0x100 //
DWORD VirtualSize; //e_lfanew + 0x104 //数据实际的节区大小
} Misc;
DWORD VirtualAddress; //e_lfanew + 0x108 //该节区载入到内存后的相对虚拟地址
DWORD SizeOfRawData; //e_lfanew + 0x10C //该节区在磁盘上的大小
DWORD PointerToRawData; //e_lfanew + 0x110 //该节区在磁盘文件上的偏移值
DWORD PointerToRelocations; //e_lfanew + 0x114
DWORD PointerToLinenumbers; //e_lfanew + 0x118
WORD NumberOfRelocations; //e_lfanew + 0x11C
WORD NumberOfLinenumbers; //e_lfanew + 0x11E
DWORD Characteristics; //e_lfanew + 0x120 //节区属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; //该数据结构大小为40字节
Characteristics(节区属性)
宏定义 值 意义
#define IMAGE_SCN_CNT_CODE 0x00000020 该节区含代码
#define IMAGE_SCN_MEM_SHARED 0x10000000 该节区为可共享
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 该节区为可执行
#define IMAGE_SCN_MEM_READ 0x40000000 该节区为可读
#define IMAGE_SCN_MEM_WRITE 0x80000000 该节区为可写
上面是为了更加熟悉PE文件。
最后,介绍一块PE工具PEView :
https://pan.baidu.com/s/1L2dGaawb_qoRF7px5X3oiw
可以直观的看到PE各个结构体的值