PE文件格式

本文详细介绍了PE文件格式,包括DOS头、DOS存根、NT头(文件头和可选头)、节区头(如.text、.data、.rdata和.idata,特别是导入表)等内容,展示了helloworld.exe文件的实例,重点讲解了如何定位和理解PE文件中的关键信息和动态链接库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 例如像.exe .elf .all .sys为后缀的文件都是PE文件,下面以hello world.exe文件作为分析样本。
  2. 下面是PE文件的整体结构:

PE头:

  1. 学习PE文件格式主要学习的时PE文件的PE头,如何加载到内存,从何处开始运行、运行中需要的动态来链接库DLL有哪些、需要多大的堆/栈内存等,都以结构体的形式储存在PE头中。
  2. PE头包含一下几个部分:DOS头,DOS存根,NT头,.text(代码)(节区头),.data(数据)(节区头),.rsrc(资源节)(节区头)。

DOS头

  1. 在这里插入图片描述

  2. DOS头结构体如下:

  3. DOS头最重要的成员有两个:第一个e_magic : 前两个字节指明了DOS签名4D5A(MZ),第二个:e_lfanew,指明了NT头在文件内的偏移。

DOS存根

  1. DOS存根部分是上个时代遗留下来的产物,在windos平台下不会执行这段命令,但是在DOS环境下运行时会执行,显示出”This program cannot be run in DOS mode“,DOS存根为的就是在DOS环境下显示一些有用的信息二存在。
  2. 在DOS下查看,前13个字节会被翻译成汇编代码,调用了21号中断的09号功能,来显示后面字符串的内容:

NT头

  1. 根据DOS头最后的4个字节找到PE头在文件中的偏移:
  2. NT头结果提如下:=
  3. 首位的4个字节为签名:50 4F 00 00 -> “PE
  4. 其次是一个文件头(IMAGE_FILE_HEADER)和可选头(IMAGE_OPTIONAL_HEADER),下面来分别查看这两个结构体
NT头:文件头
  1. 去掉前面4个字节的标识后,后面的20个字节就是NT头的文件头:
  2. 第一个Machine指明了运行平台,每个CPU都拥有唯一的Machine码。
  3. 第二个NumberOfSections指明了文件中存在的节区的数目
  4. 倒数第二个SIzeOfOptionalHeader指明了后续可选头的大小为00F0(注意这个是小端序)
NT头:可选头
  1. 在这里插入图片描述
  2. 可选头的结构体如下:
  3. 其中包含的星系非常丰富,要完全认权可以自行查看微软的开发文档,则合理只介绍几个重要的结构
  4. ImageBase指出文件被加载到内存时优先装入的基地址。
  5. AddressOfEntryPoint有EP的RVA(文件被加载到内存中的相对前面ImageBase的偏移),指明了最先执行的代码的起始地址,有EIP = ImageBase+AddressOfEntryPoint,EIP寄存器指向要执行的代码。
  6. SizeOfHeader指出了整个PE头的大小。
  7. 最后一项DataDirectory,其由时IMAGE_DATA_DIRECTORY构成的数组,IMAGE_DATA_DIRECTORY结构体如下:在这里插入图片描述
  8. 第一项是RVA(加载到内存中是的偏移地址),Size(当前表的大小)。
  9. 节表的内容如下:
    10.在最后一项DataDirectory中主要重点关注,第一项导出目录(导出表) 和 第二项导入目录(导入表)
  10. 从上面可见,该hello.exe程序没有导出表,但是又一个导入表,其RVA为 : 00008000(但是这只是导入表的RVA,不是其在文件中的偏移,后面会进行转换)

节区头

  1. 节区头的结构体:
  2. Name指明了节的名字。
  3. VirtualAddress指明了节的偏移RVA(相对于ImageBase)
  4. PointerToRawData节在文件中的偏移
  5. Charactercis节的属性,是可读、可写。
.text(代码)(节区头)


2. 说明 .text节区 的RVA是 00001000,FOA是 00000400 ,之间相差了00000C00。

.data(数据)(节区头)


2. 说明 .data节区 的RVA是00003000,FOA是00002200. 之间相差了00000E00。

.rdata
  1. 说明**.rdata节区的RVA是00004000**,FOA是00002400,之间相差00001C00。
.idata,导入表

  1. 说明**.idata节区的RVA是00008000**,FOA是00003000,之间相差00005000
  2. .idata中包含导入函数的信息,即程序运行时需要调用的外部函数(或API)的信息。查看RVA:00008000刚好和前面查看的导入表RVA相同,说明.idata段的开头就是导入表的所在位置,但是现在只知道RVA(其加载到内存中后的偏移地址),并不知道其FOA(在文件中的偏移)。
  3. 但是由于.idata的RVA刚好和导入表的RVA相同,所以直接使用.idata的FOA(PointerToRawData),作为导入表的在文件中的偏移00003000,去查得导入表,其一共导入了两个库(一个占20字节,最后20字节全为0):
  4. 根据导入表的结构体:
  5. 其中那么字段指明了导入的动态链接库DLL的名字的RVA000086E8,安静其转化为FOA即可定位到该库的具体位置:000086E8-00005000(前面在idata中计算出的RVA与FOA的差值)=36E8,定位到下面这张图的位置,库的名字叫KERNEL32.dll,KERNEL32.dll是Windows操作系统中一个非常核心的32位动态链接库(DLL)文件,它对系统运行至关重要。:
  6. 查看第二个动态链接库:00008760-00005000=0003760,定位到下面这张图,msvcrt.dll在这里插入图片描述

最后给出一个PE文件的16进制编辑器中的截图,找到其中每一个头的信息,和导入表等:

  1. 原图如下:在这里插入图片描述
  2. 标识各个部分后如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值