PE文件结构:
介绍: PE格式是windows下最常用的可执行文件格式,有些应用必须建立在了解PE文件的基础上,如可执行文件的加解密、文件型病毒的查杀等。
分析PE文件,必须要了解文件是如何从磁盘被装载到内存中去的。因此,让我们先熟悉一下PE文件的基本结构。
DOS_HEADER
介绍: 该结构体大小为40h字节,e_magic标识了头部,e_lfanew指明PE文件头在文件中的位置,这个位置以8字节为单位对齐
NT_HEADER
介绍: 整个NT_HEADER结构体大小为F8,NT_HEADER结构包含了FILE_HEADER结构和OPTIONAL_HEADER32结构
- FILE_HEADER结构
其中 Characteristics字段:它的不同数据位(16位)定义了不同的文件属性,不同的定义影响系统对文件的装入方式;
当13位为1:表示这是DLL文件,系统将使用调用DLL入口函数的方式调用文件入口。对于普通可执行PE文件,该字段值为010fh,对于DLL文件来说,这个字段通常为210eh。
-
OPTIONAL_HEADER32结构
其中一些重要字段代表的含义:
Address of entrypoint: 程序执行EP的RVA
ImageBase:表示文件的优先装入地址。
通常默认EXE(00400000h),DLL(10000000h)。若优先装入地址被其他模块使用,需要进行重定位操作,例如DLL文件。
FileAlignment: 节区存储在硬盘文件中时的最小单位
SectionAlignment: 节区被装入内存后的最小单位
SizeofImage: 加载PE文件到内存时,占用的虚拟内存空间大小
data_directory结构体数组个数: 16 -
DATA_DIRECTORY结构
各字段介绍:
PE文件到内存映射的几个问题
- 装载PE文件时,不同节区对应内存页的属性需要根据节的属性来设置;
- 节的起始地址在磁盘文件中是按照FileAlignment字段的值对齐的;而被载入到内存中时,是按照Section Alignment字段的值对齐的
- Windows系统中对内存属性的设置是以页为单位进行的,故节在内存中的对齐单位至少为一个页的大小。对于win32,该值为4KB(1000h),对于win64,该值为8KB。磁盘文件的对齐单位没有限制,小于内存页的对齐单位,通常FileAlignment为200h。
- 节尺寸的处理:
由于磁盘映像和内存映像在对齐单位上的差别,导致节区长度变化;
未初始化数据的节的处理,磁盘文件未预留空间,装载到内存时需要为其分配空间 - 重定位数据.reloc节仅供windows装载器使用,不会被映射到内存
节区头(节表)
介绍: 节表定义了各节区的属性,每一个节区由一个数据结构体描述,结构体总数等于节区总数
VirtulAddress: 对应节区在内存中的偏移地址(RVA)内存页对齐,sectionaligment整数倍
SizeOfRawData: 节区在硬盘中所占大小,等于Virtualsize按照filealigment对齐后的大小
PointerToRawDate: 节区在硬盘文件中的偏移量,从文件头算起
RVA 的计算
介绍: RVA,相对虚拟地址,是一个偏移量。PE文件中大部分数据结构涉及的地址均用RVA表示。RVA是文件加载到内存后,某个数据的位置相对于文件头的偏移量。
例如:某个PE文件被加载到处的内存中,某个节区中某个数据被装入0040xxxxh处,那么该数据的RVA= 0040xxxxh- 00400000h=xxxxh
因此,RVA加上文件被装载的内存基地址,就等于数据在内存中的实际地址。
注意: RVA仅用于确定节中数据的位置,而对文件头和节表无意义
学习PE文件格式核心是学习PE头中的结构体
主要围绕着以下四个问题来学:
- 文件如何加载到内存
- 从何处开始运行
- 运行中需要哪些DLL
- 需要多大的栈/内存