PE文件格式
目录
介绍
PE文件格式
种类编辑
基本结构
VA&RVA
PE头
DOS头
NT头:文件头
NT头:文件头
NT头:可选头
目录
介绍
PE文件格式
种类编辑
基本结构
VA&RVA
PE头
DOS头
NT头:文件头
NT头:文件头
NT头:可选头
节区头
暂时看了这么多,后面内容会在补充~~
介绍
PE文件是Windows操作系统下使用的可执行文件。PE文件是指32位的可执行文件,也称为PE32。64位的可执行文件称为PE+或者PE32+,是PE文件的一种扩展形式。
PE文件格式
种类
严格的说,OBJ(对象)文件之外的所有文件都是可执行的,DLL,SYS文件等虽然不能直接在shell中运行,但是可以使用其他方法(调试器,服务等)执行。
基本结构
从DOS头(DOS header)到节区头(Section header)是PE头部分,其他的节区合称PE体。文件使用偏移(offset),内存中使用VA(虚拟地址)来表示位置。各节区头定义各节区在文件或内存中的大小,位置,属性。
VA&RVA
VA指的是进程虚拟内存的绝对地址,RVA是相对地址,他们满足关系
RVA+ImageBase=VA.
PE头
DOS头
为了充分考虑PE文件对DOS文件的兼容性,在PE头前面添加了IMAGE_DOS_HEADER结构体,结构如下:
其结构体大小64字节,其中需要知道2个重要成员:
e_magic:DOS签名
e_lfanew:指示NT头的偏移,即真正的PE文件头(不同文件拥有可变值)
其中e_lfanew的偏移为+3C,如下演示:
可以看到DOS签名和e_lfanew为100h,那查找一下,正好是PE文件头。
NT头:文件头
IMAGE_NT_HEADERS其中第一个成员为签名结构体,值为50450000h(“PE”00),另外两个成员是文件头与可选头。
IMAGE_NT_HEADERS结构体大小为F8。
NT头:文件头
如下演示:
其中第一个,第二个,第六个,第七个比较重要,记住。
NT头:可选头
IMAGE_OPTIONAL_HEADER结构
typedef struct _IMAGE_OPTIONAL_HEADER {
+18h WORD Magic; //标志字,ROM映像(0107h),普通可执行文件(010Fh)
+1Ah BYTE MajorLinkerVersion; //链接程序的主版本号
+1Bh BYTE MinorLinkerVersion; //链接程序的次版本号
+1Ch DWORD SizeOfCode; //所有含代码的节的总大小
+20h DWORD SizeOfInitializedData; //所有含已初始化数据的节的总大小
+24h DWORD SizeOfUninitializedData; //所有含未初始化数据的节的大小
+28h DWORD AddressOfEntryPoint; //程序执行入口RVA
+2Ch DWORD BaseOfCode; //代码的区块的起始RVA
+30h DWORD BaseOfData; //数据的区块的起始RVA
+34h DWORD ImageBase; //程序的首选装载地址
+38h DWORD SectionAlignment; //内存中的区块的对齐大小
+3Ch DWORD FileAlignment; //文件中的区块的对齐大小
+40h WORD MajorOperatingSystemVersion;
+42h WORD MinorOperatingSystemVersion;
+44h WORD MajorImageVersion;
+46h WORD MinorImageVersion;
+48h WORD MajorSubsystemVersion;
+4Ah WORD MinorSubsystemVersion;
+4Ch DWORD Win32VersionValue;
+50h DWORD SizeOfImage; //映像装入内存后的总尺寸
+54h DWORD SizeOfHeaders; //所有头+区块表的尺寸大小
+58h DWORD CheckSum;
+5Ch WORD Subsystem; //可执行文件期望的子系统
+5Eh WORD DllCharacteristics;
+60h DWORD SizeOfStackReserve;
+64h DWORD SizeOfStackCommit;
+68h DWORD SizeOfHeapReserve;
+6Ch DWORD SizeOfHeapCommit;
+70h DWORD LoaderFlags;
+74h DWORD NumberOfRvaAndSizes; //下边数据目录的项数,这个字段自windows NT发布以来一直是16
+78h IMAGE_DATA_DIRECTORY DataDirectory //数据目录表[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
在 IMAGE_OPTIONAL_HEADER32结构体中需要关注下列成员,这些值是文件运行必须的,错误将导致文件不能正常运行。
#1.Magic
在IMAGE_OPTIONAL_HEADER32结构体时,Magic码为10B,IMAGE_OPTIONAL_HEADER64结构体时,Magic码为20B。
#2.AddressOfEntryPoint
持有EP的RVA值,该值指出程序最先执行的代码起始地址
#3.ImageBsae
进程虚拟内存范围0-FFFFFFFF(32位系统)。EXE,DLL文件被装载到用户内存为0-7FFFFFFF,SYS文件被载入内核内存的80000000-FFFFFFFF,一般而言,使用VC++/VB/Delphi创建exe,其基址为00400000,DLL文件的基地址10000000,。
#4.SectionAlignment,FileAlignment
FileAlignment指定了节区在磁盘文件中的最小单位,SectionAlignment指定了节区在内存中的最小单位。磁盘文件或内存的节区大小必定为FileAlignment或SectionAlignment值的整数倍
#5.SizeOfImage
加载PE文件到内存时,指定了PE IMAGE在虚拟内存中所占空间大小。
#6.SizeOfHeaders
指出整个PE头的大小。该值也必须是FileAlignment整数倍。第一节区所在位置与SizeOfHeaders距文件开始偏移的量相同
#7.Subsystem
用来区分系统驱动文件与普通可执行文件
#8.NumberOfRvaAndSizes
用来指定DataDirectory数组的个数
#9.DataDirectory
它是由IMAGE_DATA_DIRECTORY结构体组成的数据,数组的每项都有被定义的值,这个结构分为2个部分:
VirtualAddress Dword ?; 数据起始RVAisize Dword ?; 数据块的长度
DataDirectory结构体数组:
DataDirectory[0] = EXPORT Directory //导出表
DataDirectory[1] = IMPORT Directory //导入表
DataDirectory[2] = RESOURCE Directory //资源
DataDirectory[3] = EXCEPTION Directory //异常(具体资料不详)
DataDirectory[4] = SECURITY Directory //异常(具体资料不详)
DataDirectory[5] = BASERELOC Directory //重定位表
DataDirectory[6] = DEBUG Directory //调试信息
DataDirectory[7] = COPYRIGHT Directory //版权信息
DataDirectory[8] = GLOBALPTR Directory //具体资料不详
DataDirectory[9] = TLS Directory //Thread Local Storage
DataDirectory[A] = LOAD_CONFIG Directory //具体资料不详
DataDirectory[B] = BOUND_IMPORT Directory //具体资料不详
DataDirectory[C] = IAT Directory //导入函数地址表
DataDirectory[D] = DELAY_IMPORT Directory //具体资料不详
DataDirectory[E] = COM_DESCRIPTOR Directory //具体资料不详
DataDirectory[F] = Reserved Directory //未使用
节区头
节区头中定义了各节区属性。把PE文件创建成多个节区结构的好处是,这样可以保证程序的安全性。
IMAGE_SECTION_HEADER
#define IMAGE_SIZEOF_SHORT_NAME 8 typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; // \0结尾的节的名称 union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; //节区的RVA地址 DWORD SizeOfRawData; //在文件中对齐后的尺寸 DWORD PointerToRawData; //在文件中的偏移量 DWORD PointerToRelocations; //在“.obj”文件中使用,指向重定位表的指针 DWORD PointerToLinenumbers; //行号表的偏移(调试用) WORD NumberOfRelocations; //重定位表的个数(“.obj”文件) WORD NumberOfLinenumbers; //行号表中行号的数量 DWORD Characteristics; //节的属性,如可读可写可操作 } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
其中重要的成员如下:
如下进行演示: