<p id="main-toc"><strong>目录</strong></p>
讯享网
一般概述
名字解释
PE 文件的模块介绍
IMAGE_DOS_HEADER:
IMAGE_NT_HEADERS:
节表
windows 下的可执行文件是一个exe ,采用额是PE格式来描述一个执行文件,执行的时候**作系统中的加载器加载到内存中。先展示一个exe 按照PE格式解析出来的结果。
讯享网
下面的表格是从微软官方获取的名词解释:
在目标文件中,RVA 的意义不大,因为未分配内存位置。 在这种情况下,RVA 将是一个段内的地址(此表后面将进行描述),稍后在链接期间会对此地址应用重定位。 为简单起见,编译器应只将每个部分中的第一个 RVA 设置为零。sectionPE 或 COFF 文件中代码或数据的基本单位。 例如,目标文件中的所有代码都可以组合在单个部分中,或者(取决于编译器行为)每个函数都可以占用自己的部分。 部分越多,文件开销就越大,但链接器能够更有选择性地链接代码。 一个部分类似于 Intel 8086 体系结构中的段。 一个部分中的所有原始数据都必须连续加载。 此外,映像文件可以包含多个具有特殊用途的部分,例如 .tls 或 .reloc 。虚拟地址 (VA)与 RVA 相同,只不过不减去映像文件的基址。 该地址称为 VA,因为 Windows 会为每个进程创建一个独立于物理内存的不同 VA 空间。 对于几乎所有目的,VA 应只被视为一个地址。 VA 不如 RVA 那么可预测,因为加载器可能不会在其首选位置加载映像。
下面我们来一个个解析PE文件的每一个模块:
IMAGE_DOS_HEADER:
DOS头的作用是兼容MS-DOS操作系统中的可执行文件,对于32位PE文件来说,DOS所起的作用就是显示一行文字,提示用户:我需要在32位windows上才可以运行。
讯享网
执行文件用十六进制显示
我们只需要关注两个域:
e_magic:一个WORD类型,值是一个常数0x4D5A,用文本编辑器查看该值位‘MZ’,可执行文件必须都是'MZ'开头。
e_lfanew:为32位可执行文件扩展的域,用来表示DOS头之后的NT头相对文件起始地址的偏移。
从图中可以看到是0x000000e8 这个位置,所以下一个位置就是NT的头
DOS存根位于DOS头下方,是个可选项,且大小不固定,即使没有DOS存根,文件也能正常运行,DOS存根由代码与数据混合而成
IMAGE_NT_HEADERS:
顺着DOS头中的e_lfanew,我们很容易可以找到NT头,这个才是32位PE文件中最有用的头

Signature:类似于DOS头中的e_magic,其高16位是0,低16是0x4550,用字符表示是'PE‘。
讯享网
Machine:Machine:该文件的运行平台,是x86、x64还是I64等等
NumberOfSections:该PE文件中有多少个节,也就是节表中的项数。
TimeDateStamp:PE文件的创建时间,一般有连接器填写。
PointerToSymbolTable:COFF文件符号表在文件中的偏移。
NumberOfSymbols:符号表的数量。
SizeOfOptionalHeader:紧随其后的可选头的大小。
Characteristics:可执行文件的属性,可以是下面这些值按位相或。
IMAGE_OPTIONAL_HEADER32
Magic:表示可选头的类型。
MajorLinkerVersion和MinorLinkerVersion:链接器的版本号。
SizeOfCode:代码段的长度,如果有多个代码段,则是代码段长度的总和。
SizeOfInitializedData:初始化的数据长度。
SizeOfUninitializedData:未初始化的数据长度。
AddressOfEntryPoint:程序入口的RVA,对于exe这个地址可以理解为WinMain的RVA。对于DLL,这个地址可以理解为DllMain的RVA,如果是驱动程序,可以理解为DriverEntry的RVA。
BaseOfCode:代码段起始地址的RVA。
BaseOfData:数据段起始地址的RVA。
ImageBase:映象(加载到内存中的PE文件)的基地址,这个基地址是建议,对于DLL来说,如果无法加载到这个地址,系统会自动为其选择地址。
SectionAlignment:节对齐,PE中的节被加载到内存时会按照这个域指定的值来对齐,比如这个值是0x1000,那么每个节的起始地址的低12位都为0。
FileAlignment:节在文件中按此值对齐,SectionAlignment必须大于或等于FileAlignment。
MajorOperatingSystemVersion、MinorOperatingSystemVersion:所需操作系统的版本号,随着操作系统版本越来越多,这个好像不是那么重要了。
MajorImageVersion、MinorImageVersion:映象的版本号,这个是开发者自己指定的,由连接器填写。

MajorSubsystemVersion、MinorSubsystemVersion:所需子系统版本号。
Win32VersionValue:保留,必须为0。
SizeOfImage:映象的大小,PE文件加载到内存中空间是连续的,这个值指定占用虚拟空间的大小。
SizeOfHeaders:所有文件头(包括节表)的大小,这个值是以FileAlignment对齐的。
CheckSum:映象文件的校验和。
Subsystem:运行该PE文件所需的子系统
SizeOfHeapReserve:运行时为进程堆保留内存大小。
SizeOfHeapCommit:运行时进程堆初始占用内存大小。
LoaderFlags:保留,必须为0。
NumberOfRvaAndSizes:数据目录的项数,即下面这个数组的项数。
DataDirectory:数据目录,这是一个数组,数组的项定义如下:
讯享网
VirtualAddress:是一个RVA。
Size:是一个大小。
DataDirectory 的每一项就不一一的介绍。
程序的真正入口点 = ImageBase + AddressOfEntryPoint
节表
先简单介绍一下基本节表的功能,这些节表在被加载器加载的时候读取,根据具体的内容获取相应的节中的具体数据。
bss段(Block(b) Started(s) by Symbol(s)):即用来存储一些未被初始化的全局变量和静态变量的内存区域,一般在初始化时bss段部分将会清零,属于静态内存分配,即程序一开始就将其清零了。
特点:可读写。
data段:又称为数据段,通常是指用来存放程序中已被初始化的全局变量,常量,静态变量的一块内存区域。也就是我们通常说的静态存储区。
特点:可读写。
text段 (textsegment):通常指用来存放程序执行代码的一块内存区域,这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。
在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
特点:只读
rdata段:该段也叫常量区,用于存放常量数据,ro就是read only(只读)。
特点:只读
段:通常指的是导入表(Import Table)的部分
特点:只读
段(或称为节,Section)是重定位表(Relocation Table)的存储位置
特点:只读
rsrc段是一个标准的段,用于存放程序的资源。这些资源可以包括图标、光标、位图、菜单、对话框、字符串表、字体等,它们都是程序用户界面和功能的重要组成部分。通过将这些资源存储在.rsrc段中,程序可以在运行时动态地访问和使用它们,而不需要将它们硬编码到程序中。
特点:只读
下面是一个windows 32 位程序的内存分布。
显示当前的exe 文件中有多少给个section
根据内容对每一个section 做一个解析
看第一个节表的数据
按照数据结构解析出来的结果

可以看到 section的一些基本信息,Size of Raw Data 的值是0。BSS段不包含任何数据,只是简单的维护开始和结束的地址,以便内存区能在运行时被有效的清零。并不给该段的数据分配空间,只是记录数据所需空间的大小。不占用可执行文件的空间,BSS段在应用程序的二进制映像文件中并不存在。
再看一下text 节

根据他们的pointer of Raw Data和Size of Raw Data 可以定位出Section的具体数据从0x400 位置一直到79ff 。
RVA 显示的是这些段在内存中的偏移地址,根据段基址和偏移地址可以算出来线性地址,如果没有分页机制,线性地址就对应物理地址,如果有分页机制根据映射关系从线性地址转换成物理地址。
本文简单介绍了PE文件的格式,后续再对重定位,导入表等做一些详细的介绍。
IMAGE_NT_HEADERS:
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/208284.html