这两天对于PE的学习总结:
1.PE结构的应用
(1)windows下exe文件
(2)动态链接库(大部分是以dll为扩展名得文件)
2.关于PE分节
(1)节省硬盘空间 (2)一个应用程序多开
对齐 | 旧式的电脑 | 新款 |
硬盘对齐 | 200h | 1000h |
内存对齐 | 1000h | 1000h |
3.PE整体结构
DOS头 NT头 节表/块表 .text块 .rdata块 data块
(后面这几个快不确定位置和数量,这些由节表确定)
下面介绍的都是几个头中重点的几个标识,所以详细的自己百度
4. DOS头(一般运用在16位系统中 )
WORD e_magic * "MZ标记" 用于判断是否为可执行文件. (即判断是否在windows上执行)
DWORD e_lfanew; * PE头相对于文件的偏移,用于定位PE文件
DOS头和NT头之间由垃圾数据填充
5.NT头
NT头分为三部分(1)PE标记(2)标准PE头(3)可选PE头
(1)PE标记
dword signature (由DoS头里e_lfanew确定位置)
(2)标准PE头 fileheader
WORD Machine; * 程序运行的CPU型号:0x0 任何处理器/0x14C 386及后续处理器
WORD NumberOfSections; * 文件中存在的节的总数,如果要新增节或者合并节 就要修改这个值.
DWORD TimeDateStamp; * 时间戳:文件的创建日期和时间(和操作系统的创建时间无关),编译器填写的.
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader; * 可选PE头的大小,32位PE文件默认E0h 64位PE文件默认为F0h 大小可以自定义.
WORD Characteristics; * 文件属性,每个位有不同的含义,普通exe文件值为10Fh 即0 1 2 3 8位置1 Dll文件一般是210Eh
(3)可选pe头 optionalheader(由标准pe头里sizeOfOptionalHeader确定)
WORD Magic; * 说明文件类型:10B 32位下的PE文件 20B 64位下的PE文件
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;* 所有代码节的和,必须是FileAlignment的整数倍 编译器填的 没用
DWORD SizeOfInitializedData;* 已初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的 没用
DWORD SizeOfUninitializedData;* 未初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的 没用
DWORD AddressOfEntryPoint;* 程序入口
DWORD BaseOfCode;* 代码开始的基址,编译器填的 没用
DWORD BaseOfData;* 数据开始的基址,编译器填的 没用
DWORD ImageBase;* 内存镜像基址
DWORD SectionAlignment;* 内存对齐
DWORD FileAlignment;* 文件对齐
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;* 内存中整个PE文件的映射的尺寸,可以比实际的值大,但必须是SectionAlignment的整数倍
DWORD SizeOfHeaders;* 所有头+节表按照文件对齐后的大小,否则加载会出错
DWORD CheckSum;* 校验和,一些系统文件有要求.用来判断文件是否被修改.
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;* 初始化时保留的堆栈大小
DWORD SizeOfStackCommit;* 初始化时实际提交的大小 DOS
DWORD SizeOfHeapReserve;* 初始化时保留的堆大小 ...
DWORD SizeOfHeapCommit;* 初始化时实践提交的大小 PE标记
DWORD LoaderFlags; 标准PE
DWORD NumberOfRvaAndSizes;* 目录项数目 可选PE头
6.节表(由标准PE头里NumberOfsections可知节表数目)
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
1、Name 8个字节 一般情况下是以"\0"结尾的ASCII吗字符串来标识的名称,内容可以自定义.
注意:该名称并不遵守必须以"\0"结尾的规律,如果不是以"\0"结尾,系统会截取8个字节的长度进行处理.
2、Misc 双字 是该节在没有对齐前的真实尺寸,该值可以不准确。
3、VirtualAddress 节区在内存中的偏移地址。加上ImageBase才是在内存中的真正地址.
4、SizeOfRawData 节在文件中对齐后的尺寸
5、PointerToRawData 节区在文件中的偏移.
6、PointerToRelocations 在obj文件中使用 对exe无意义
7、PointerToLinenumbers 行号表的位置 调试的时候使用
8、NumberOfRelocations 在obj文件中使用 对exe无意义
9、NumberOfLinenumbers 行号表中行号的数量 调试的时候使用
10、Characteristics * 节的属性
(这是一个节表信息,几个节表信息连续)
7.三种不同的地址
文件中的地址(FA): 在文件地址空间中,文件载入的起始位置总是等于0,FA地址表现为一个偏移地址;
虚拟地址(VA):PE文件被映射到内存中时,在内存中的映射地址;
相对偏移地址(RVA):程序某一结构的VA减去FA的结果;
程序被装载入内存中时,由文件结构不变,故其RVA不变,但装载起始地址不变,因为很难保证计算机的运行状态时时刻刻都是一致的。