PE学习
1、主要结构体
DOS MZ文件头的内存大小为64个字节
DOS Stub的大小不确定,因为这段是给连接器用的,即使这段数据被删改也不影响运行
通过DOS MZ文件头尾到PE文件头的内存确定大小
DOS部分属于是历史遗留问题,用于DOS 操作系统与exe程序运行无关,只是保留在PE中
PE文件头由三个部分组成,PE标识(PE指纹)类型为DWORD 占四个字节、标准PE头和扩展PE头
标准PE头的大小为20个字节,扩展PE头是224个字节(32位)(主要原因是其中包括了一个结构体数组)
扩展PE头可以产生变化,其主要取决于结构体中的 WORD SizeOfOptionalHeader 变量
之后就是节表,其所占字节为40个字节。其中包含了几个节数据,在节数据之后的全都是编译器插入的其他数据(节数据数量不定,可以进行修改)
扩展PE头中有一个结构体变量是DWORD SizeOfHeaders 这个变量的数值代表着DOS 部分、PE文件头和节表在文件对齐后的大小。 文件对齐对应的变量是DWORD FileAlignment 在头之后,就是各个节数据
扩展PE头中还有一个DWORD SectionAlignment 这个代表的内存对齐,一般来说与文件对齐数据不同。 两种状态不同,主要是指的是 头跟节,节跟节之间的距离不同,一般来说在内存中都是拉伸之后的。
为什么在文件中的对齐参数和在内存中不同?
内存对齐是为了提高内存利用效率,充分利用系统总线。 文件对齐是为了提高解析的效率
为什么PE文件在设计的时候要分块?
分块的一个原因是节省硬盘,而分块的另一个目的是节省内存空间。
一个PE文件加载进内存中可能大于在硬盘上的大小,并且无论是在内存中还是硬盘上,都是是分块管理(分节),一块和一块存储空间之间是空隙。在硬盘上空隙有可能小于内存中空隙;在内存中空隙较大(相较于硬盘)。而存在间隙的原因则是分块管理。 分块的一个原因是节省硬盘:比如notepad.exe,由于是早期的程序,当时硬盘容量比较小,编译器在生成可执行文件时,不仅要考虑效率问题使得内存对齐/文件对齐,还需要设计成节省硬盘空间的结构。所以这种结构遵循的对齐原则:内存对齐(1000H)和硬盘对齐(200H),对齐的补充数据(0X0000)便是间隙。硬盘的对齐值较小,补充间隙自然小,因此同一个可执行程序在内存中可能比在硬盘上大。但是现如今的硬盘空间更大,所以编译器生成的可执行程序在硬盘上与内存中对齐方式都是1000H。统一对齐为1000H的目的依旧是提高效率。 而分块的另一个目的是节省内存空间,比如同时在电脑上运行登录多个QQ账号,就需要运行多次QQ可执行程序。而代码段为只读数据需要一份即可,数据段则需要为每个账号均开辟一份,,多个QQ程序共享代码块,单独使用数据块,这样就节省了多份代码块的内存。(这些块是使用结构体来维护的,分块即创建结构体)。
2、DOS头属性说明
DOS部分由DOS块和DOS MZ文件头组成,DOS块不是结构体而是由单个字节组成的数据可以填写任何内容 ,而DOS MZ文件头是一个结构体 ,该结构体如下图组成
但该结构体是运行在16位操作系统上的,如今不再使用
但有其中两个成员是例外 WORD e_magic和WORD e_lfanew
即为第一和最后一个成员,如果将他们中间的成员都删除也不影响程序的使用,主要是因为第一个成员是一个标识,其代表的是PE指纹其内容应该是MZ,操作系统以此来判断一个程序是否是PE,最后一个成员指明的了PE的位置 ,操作系统以这两个特征来标识是PE文件,而如果进行了修改,再去点击该程序就会出现下面的情况
DOS块中的数据是由连接器进行填写的,将其中的进行修改也不会影响运行
3、标准PE头属性说明
PE文件头(_IMAGE_NT HEADERS)部分结构体分为了三个部分分别是:
typedef struct_IMAGE_NT_HEADERS{
DWORD Signature; //PE标识
IMAGE_FILE_HEADER FileHeader; //标准PE头
IMAGE_OPTIONAL_HEADER32 OptionalHeader; //扩展PE头
}IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
PE标识:PE标识不能破坏,操作系统在启动一个程序的时候会检测这个标识。
typedef struct_IMAGE_FILE_HEADER (
WORD Machine;
//可以运行在什么样的CPU上 任意: O Intel 386以及后续: 14C x64: 8664
WORD NumberOfSections;//表示节的数量
DWORD TimeDateStamp;//编译器填写的时间截与文件属性里面(创建时间、修改时间)无关
DWORD PointerToSymbolTable; //调试相关
DWORD NumberOfSymbols;//调试相关
WORD SizeOfOptionalHeader; //可选PE头的大小(32位PE文件: OxEO 64位PE文件: OxFO)
WORD Characteristics;//文件属性
}IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
标准PE头的第一个成员是代表了可以运行在什么样的CPU上,即在PE标识后面的一个四个字节的数据,如果是0000,即可以运行在任意CPU上,如果是Intel386以及后续的是014C(包含X86),X64的是8664
第二个成员指的是节的数量(即节数据的个数)
第三个成员为四个字节,其中填写的是时间戳,即从1970.1.1 0时0分开始 ,每过一秒编译器就往里面添1。(其与文件创建时间和修改时间无关。我们也可以通过自己的需求进行修改
第四个和第五个是与调试相关的
第六个成员指的是扩展PE头的大小。如果是32位的PE文件,则该成员的数据是0xE0 64位的数据是0xF0
最后一个成员指的是文件属性,是两个字节,16位的数据
十六位的数据其中每个位有其代表的含义,如上图所示。
其中第五个数据位的代表,应用程序可处理大于2GB的地址。我们知道的是在32位操作系统中,应用能够处理的一共是4GB的地址,其中高2G的地址由内核部分使用,低2G的地址是由应用程序使用。故由此可知,此数据位代表的是应用程序是64位的。
4、扩展PE头属性说明
typedef struct _IMAGE_NT_HEADERS{
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
}IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
}IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
PE头在32位和64位是不同的,上述代码上面的是32位,下面的是64位,且不同的地方主要在于扩展PE头,主要差异是该结构体里面少了几个成员,同时部分成员由2个字节变为4个字节。
我们这里主要研究32位的扩展PE头,64位的大同小异
//大小: 32bit(0xE0) 64bit(0xF0)
上面结构体即是32位的扩展PE头,其中的成员不必全部记忆,只用记忆注释中带有符号的 “ !!!!!****!!!!!”
第一个成员 WORD Magic; 这个成员是 识别该文件是32位还是64位的文件最为准确的方式,如果其中的数值是10B即为32位的文件,而如果其中的数值是20B就是64位的文件。
往后五个都是有关于链接器和编译器的,前两个分别是版本号,后三个是由编译器填写的一些统计数据,如果进行修改,其实对于运行也并不影响。
我们先来看这个DWORD ImageBase(内存镜像基址),因为每一个进程都有自己对应的4个G的虚拟内存,因为程序在硬盘中和内存中的状态不同,在内存中会根据文件对齐而展开,而这个ImageBase则决定了从哪里开始展开。
而在内存中包含了数据和程序,DWORD AddressOfEntryPoint则代表了该对应的程序是从哪里开始的,其代表了程序的入口。
然后,DWORD FileAlignment和DWORD SectionAlignment则已经在前面介绍过了,其代表了PE文件在内存和硬盘中的状态。
DWORD SizeOfImage这个成员代表了,PE文件在内存中映射的大小,一般来说都是比硬盘中的实际大小要大,因为内存对齐的原因,所以其大小需要是SectionAlignment的整数倍。DWORD SizeOfHeaders而这个就代表了是PE文件在硬盘中按照内存对齐后的大小。
DWORD CheckSum即为所有的文件内容加上文件长度,最后得到的一个四个字节的数据,以此来判断系统文件是否被修改。但是这样并不能保证文件是否真正未被修改,因为当我们修改文件的时候我们也会同时将该数据进行修改。
WORD DllCharacteristics则是文件特性,但不是针对DLL文件的
因为是WORD的大小,所以是一个字节的大小,一个字节16位,每一位都有它对应的含义。
DWORD NumberOfRvaAndSizes代表了有多少个表,而这些表则代表了之后的结构体数组的长度。
其他的成员,就不过多赘述,因为重要性相较于上面的几个不是那么大。做简单的了解就可以了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报