PE结构(二)PE头字段说明

news2024/11/18 3:39:36

PE头字段 = DOS头 + PE标记 + 标准PE头 + 可选PE头

我们今天分析一下PE头字段中所有重要成员的含义

DOS头

DOS头中我们需要去分析的是如下两个成员:

1.WORD e_magic:MZ标记,用于判断是否为可执行文件,即如果显示4D 5A,说明该文件是一个可执行文件,如:.sys/.dll/.exe等

2.DWORD e_lfanew:NT头(PE签名)相对于文件首地址的偏移,用于定位PE文件真正开始的地址,但该值不是固定的

PE标记

该PE标记的地址即e_Ifanew指向的地址

PE标记中我们要分析的成员只有这一个:

DWORD Signature;  该值存储的是PE两个字,用来表示该文件是PE文件,因此一个可执行文件应该同时满足MZ标记和PE标记,如果这两点不满足可能被修改过,或者就不是一个可执行文件

标准PE头

标准PE头中我们需要去分析的是如下几个成员:

1.WORD Machine:用于约定该文件能在什么样的CPU上运行:如果是0x00表示能在任何CPU上执行,如果是0x14C表示能在386及后续CPU上执行

2.WORD NumberOfSections:用于告知该PE文件中分节的总数(不包括DOS头、NT头、节表):如果要新增节或者合并节,就要修改这个值。

4.DWORD TimeDateStamp:时间戳:文件的创建时间(和操作系统的创建时间无关),当程序被编译器编译时,由编译器填写的

时间戳的使用案例:比如现在要给一个.exe文件加壳,有些加壳软件不光要提供给.exe文件,还需要其对应的.map文件。.map文件中记录了此.exe文件中的所有的函数的名字、地址、参数等信息。这两个文件由编译器编译源文件时生成,.map和.exe的时间戳是一致的。如果现在这个.exe文件被反复修改了以后,.exe文件的时间戳就会改变,但是map的时间戳没有更新,这会导致exe和map不同步。此时如果加壳还是按照map中的记录信息去加壳,就可能出现错误。所以很多加壳软件在加壳之前会检查exe和map文件的时间戳是否一致

5. WORD SizeOfOptionalHeader:可选PE头的大小,该大小不确定:32位PE文件默认E0h,64位PE文件默认为F0h,但其大小可以自定义

6. WORD Characteristics:特征:其大小16位的每个位都表示不同的特征,可执行文件值一般都是0x010F。当某位为1时,表示此文件有此位对应的特征,为0时表示没有此特征

characteristic每一位表示的含义如下图:

把内存中的值读出来后,即读作0x010F,此时化成二进制,第七位省略,其他的每一位都表示一个特征,如果为1,则表示此文件有此位对应的特征;为0表示没有此特征

可选PE头

可选PE头中我们需要去分析的是如下几个成员:

  1. Magic:说明文件类型:如果值为0x010B,表示是32位下的PE文件;如果值为0x020B,表示是64位下的PE文件
  2. SizeOfCode:所有代码节大小的和,必须是FileAlignment的整数倍

比如文件只有一个代码节,大小为100h字节,如果文件对齐粒度是200h,那么会补0填充够200h字节,所以会显示200h(编译器填的);若文件有两个代码节,两个都是10字节,这个值应为400h。但是计算机发展到现在已经不使用这个值了,改了也没事,删除它程序也可以正常运行,但是现在之所以保留下来是因为向下兼容之前的文件

3.SizeOfInitializedData:已初始化数据(比如定义一个有值的全局变量,便是已初始化的数据)大小的和,必须是FileAlignment的整数倍:由编译器填写,目前计算机已经不使用这个值了,保留下来只是为了向下兼容。

4.SizeOfUninitializedData:未初始化数据(比如定义一个没有值的全局变量,便是未初始化的数据)大小的和,必须是FileAlignment的整数倍:编译器填的,现在没用了。

5.AddressOfEntryPoint:程序入口点OEP,即程序真正执行的起始地址:这个值是相对于文件基地址偏移的程序入口地址,而不是真正运行在内存中的程序入口地址。文件装入到4GB虚拟内存中的起始基地址 +相对于文件首地址偏移的程序入口地址,即imagebase + AddressOfEntryPoint,这个值才是真正运行在4GB虚拟内存中的程序入口地址。虽然该值在不同文件中有不同的值,但一般都是0x0040000开始,这是系统的默认ImageBase值。该值我们可以自定义修改,但要保证它可以执行

注意:程序入口在默认情况下一般都在.text节.code代码块当中,且OEP不是只能在.code代码块开始的位置,也可以从此块当中的任何合理位置,或者在其他节(如自定义.tttt节等)的任意合理位置,又或者在数据中。

6.BaseOfCode:代码开始的基址:即PE文件加载到内存后,所有代码的起始地址。编译器填写的,可以改,但不影响程序执行

7.BaseOfData:内存中所有数据开始的地址:编译器填的,程序运行用不到,想改就改

8. ImageBase: 内存镜像基址:该值可以看作模块之间的对齐粒度,也是程序运行装载到自己的虚拟4GB内存后的起始位置。imagebase一般都是0x00400000(具体原因参考上一篇对齐部分),这是系统的默认值,不能超过0x80000000,这是因为我们写的程序的数据只能在内存的2GB用户区中,不能占用2GB系统区。

模块的概念:一个.exe文件可能是由一堆PE文件组成的,每个pe文件都有自己的imagebase,他们共用一个4GB虚拟内存。这是因为.exe文件本身是一个PE文件,满足PE结构,但是.exe中可能还用到了很多.dll,每一个.dll也是一个PE文件,也满足PE结构,这些.dll有自己的功能和作用,当它们拼凑到一个.exe文件中时,.exe文件就有了完整的功能。这时又称.exe文件有很多模块构成,每一个.dll都是一个模块

pe文件(各个模块)不能从0开始的原因是因为内存保护,我们前面学过,free一个动态分配内存的指针后,一定要将指针指向NULL,那么当指针指向NULL后,这个指针指向的地址就是0x0,从0开始往后偏移一定范围的地址,操作系统都把他的地址上内存空了出来,那么此时指针访问这部分的数据,编译器会立马报错,也就是说限制了指针使其不能为所欲为的访问内存。

9.SectionAlignment:内存对齐粒度:可执行文件运行时装入4GB虚拟内存中的对齐粒度,一般为0x1000字节

10.DWORD FileAlignment:文件对齐粒度:可执行文件在硬盘的对齐粒度,一般为0x200字节,还有的是0x1000字节,和内存对齐粒度相等

举例说明内存对齐和文件对齐:(day27.1-PE结构概况中详细说明过)

11. DWORD  SizeOfImage:内存中整个PE文件的映射尺寸:即文件运行时在4GB虚拟内存中的整个文件数据大小。该值可以比实际的值大,但必须是SectionAlignment的整数倍

12. DWORD SizeOfHeaders:所有头+节表按照文件对齐后的大小:即DOS头 + 垃圾数据 + PE签名 + 标准PE头 + 可选PE头 + 节表,按照文件对齐后的大小。必须是FileAlignment的整数倍,否则加载会出错

举例:比如一个可执行文件的所有头和节表加起来大小为0x1800字节,但是因为要满足文件对齐粒度0x1000,示意图SizeOfHeaders的值应该为0x2000,

13. DWORD CheckSum:校验和:一些重要的系统文件、驱动文件等对此有要求,用来判断文件是否被修改(但是可以修改这个值)

校验方法举例:把PE文件中的所有数据中两个字节的值(十六进制)两两相加(如值1 2 3 4,相加:1+2,3+4),最后将所有两两相加的结果再求和得到一个数,存放到checksum表示的4字节内存中,内存可溢出

14. DWORD SizeOfStackReserve:初始化时保留的栈大小 (最大值)

15. DWORD SizeOfStackCommit:初始化时实际提交的栈大小

16. DWORD SizeOfHeapReserve:初始化时保留的堆大小 (最大值)

17. DWORD SizeOfHeapCommit:初始化时实际提交的堆大小

18. DWORD NumberOfRvaAndSizes:目录项数目“如果该值是0x10,表示下面的_IMAGE_DATA_DIRECTORY DataDirectory[16]结构体有16个,一个占8字节,这些结构体用于告诉我们编译器在编译文件时往exe文件中所添加的数据。具体如下图所示:

可执行文件的读取到装入内存过程

文件装入内存流程如图所示:

1.编译器生成.exePE文件

比如我们使用VC,编写程序以后按下F7,编译器会编译生成对应的.exe可执行文件,此时编译器计算生成PE文件的所有数据,比如imagebase或者OEP等全部字段信息,最后将.exe文件保存到硬盘中

2.文件数据读到内存(FileBuffer)

当文件数据读取到内存中时,其数据存储是完全照搬文件在硬盘上的数据。此时文件的格式并非windows运行格式,所以Windows操作系统还无法运行它

3.将文件装载到内存镜像(ImageBuffer)

将文件从FileBuffer装入ImageBuffer,即将文件从imagebase开始对齐拉伸成内存对齐形式的一块内存。这个过程就是将文件装入自己的4GB虚拟内存中,称为PE loader。我们称将文件拉伸装载后的内存为imageBuffer,即内存镜像。此时文件的格式满足windows运行格式。对于硬盘对齐粒度等于内存对齐粒度的文件不需要进行拉伸

此时文件在4GB虚拟内存中的起始地址,就是imagebase,一般为0x00400000,接着就可以通过imagebase + addressofentrypoint找到文件装载到内存后真正的程序入口地址;或者用imagebase加上一些偏移地址值就可以得到文件其他内容在运行时装入4GB内存后的地址

4.操作系统将虚拟地址转化成物理地址

FileBuffer和ImageBuffer提到的所有地址都是虚拟地址,操作系统最后会将这些虚拟地址转换为物理地址,这样才算真正的装入到真实内存中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1621279.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Centos7 安装zabbix agent2并测试与zabbix server的连通性

目录 1、实验环境 2、yum在线安装 2.1 查看agent2 rpm包,找到合适的rpm包 2.2 rpm安装 2.3 配置zabbix_agent2.conf 2.4启动agent2服务并将其加入到开机启动项中 3、配置防火墙放行10050端口,允许10050/tcp端口的入站流量。 4、在zabbix-server机…

云南旅游攻略

丽江景点 Day1 ——丽江古城 丽江古城是一个充满文化和历史的地方,拥有丰富的景点和活动。 推荐游玩: 参观标志性建筑:大水车是丽江古城的标志性建筑,可以在这里拍照留念。 探索中心广场:四方街是古城的中心&#xf…

从未如此清晰:了解SVG格式的终极解读!

图像质量对页面非常重要——扭曲和缩放变形的标志、图标或照片会使页面看起来粗糙和不协调,这个问题只会因为响应设计而复杂。访问者通过桌面机和智能手机查看应用程序,因此无论使用什么设备,图像都应该进行优化。如果有一个数字格式可以让图…

共享单车数据分析与需求预测项目

注意:本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 ([www.aideeplearning.cn]) 项目背景 自动自行车共享系统是传统自行车租赁的新一代,整个会员、租赁和归还过程都变得自动化。通过这些系统,用户可以…

SpringCloud系列(13)--Eureka服务名称修改和服务IP显示

前言:在上一章节中我们把服务提供者做成了集群,而本章节则是一些关于服务信息的配置,这部分知识对集群整体影响不大,不过最好还是掌握,毕竟万一有用到的地方呢 1、修改服务的名称 有时候我们想要修改服务的名称&#…

Linux网络-DHCP原理与配置

目录 一.DHCP工作原理 1.了解DHCP服务 1.1.使用DHCP的好处 1.2.DHCP的分配方式 2.DHCP的租约过程 2.1.DHCP工作原理 2.2.DHCP交互过程 二.DHCP服务器的配置 1.关闭防火墙 2.检查并且安装DHCP有关软件包 3.查看系统的配置文件 3.1.设置参数 4.修改网络 4.1.修改虚…

MATLAB命令

MATLAB是一个用于数值计算和数据可视化的交互式程序。您可以通过在命令窗口的MATLAB提示符 ‘>>’ 处键入命令来输入命令。 在本节中,我们将提供常用的通用MATLAB命令列表。 用于管理会话的命令 MATLAB提供了用于管理会话的各种命令。下表提供了所有此类命令…

Golang基础3-函数、nil相关

函数 需要声明原型支持不定参数 func sum(numbers ...int)int支持返回多值支持递归支持命名返回参数 // 命名返回参数 func add(a, b int) (sum int) {sum a breturn // 这里不需要显式地写出返回值,因为已经在函数签名中声明了命名返回参数 } 支持匿名函数、闭包…

redis基于Stream类型实现消息队列,命令操作,术语概念,个人总结等

个人大白话总结 1 在Redis Stream中,即使消息被消费者确认(acknowledged, ACK),消息也不会自动从Stream数据结构中删除。这与Kafka或RabbitMQ等传统消息队列系统的做法不同,在那些系统中,一旦消息被消费并…

Linux 服务器硬件及RAID配置实战

服务器详解 服务器分类 可以分为:塔式服务器、机架服务器、刀片服务器、机柜服务器等。 其中以机架式居多 服务器架构 服务器品牌: 戴尔、AMD、英特尔、惠普、华为、华3(H3C)、联想、浪潮、长城 服务器规格: 规格…

贵州大学计算机840初试

本人是24考研的一名考生,现在已经上岸啦。有想考贵州大学计算机的同学需要资料可以找我喔~ #希望大家都可以如愿以偿😎😎

Java web应用性能分析之客户端慢

客户端慢的原因包括: 终端设备老化(手机、PAD、电脑年限久远、运行期间产生了很多垃圾未清除)终端网络设备老化(路由器、交换机老化)跟我们使用的手机一样,路由器也需要及时更新换代,否则硬件跟…

11.泛型

文章目录 1 泛型概念2. 自定义泛型结构3 泛型方法4 泛型在继承上的体现5 通配符的使用 1 泛型概念 所谓泛型就是用标识符标识不确定的类型,详细说就是:定义类或接口时用标识符表示类中某个属性的类型或者是某个方法的返回值及参数类型。泛型将在使用时&a…

oracle 12c+ max_string_size参数

一个客户的数据库版本是19.3,在做数据库复制的时候,目标端报错了,查看了一下问题发现表的字段长度有不对,在12c以前我们都知道varchar的长度最大是4000,但是客户这里居然有32767: 把客户的建表语句弄出来,放到我的一个19c的测试环境进行测试: 发现报错了: 这里报错很明显了,是M…

力扣面试 150二叉搜索树迭代器 中序遍历 栈模拟递归 步骤拆分

Problem: 173. 二叉搜索树迭代器 思路 &#x1f469;‍&#x1f3eb; 三叶 复杂度 时间复杂度: O ( 1 ) O(1) O(1) 空间复杂度: O ( h ) O(h) O(h) Code class BSTIterator { Stack<TreeNode> d new Stack<>();public BSTIterator(TreeNode root){dfsLe…

thsi指针用法总结

1 c类对象中的变量和函数是分开存储的 2 所以对象共用一份成员函数&#xff0c;类的大小是指非静态的成员变量&#xff1b; this 完成链式操作 const 修饰成员函数

IDEA启动项目弹框提示:Lombok requires enabled annotation processing

问题现象 IDEA启动项目弹框提示如下图&#xff1a; 原因分析 由弹窗内容分析&#xff0c;首先确认我的IDEA中已经安装了Lombok插件&#xff0c;其次去settings中查找annotation processing配置&#xff0c;发现确实有这个配置并且未勾选启动 如何解决 修改配置

Linux:动静态库介绍

动静态库 库的介绍开发环境 & 编译器库存在的意义库的实现库的命名静态库制作和使用总结 动态库的制作和使用动态库的使用方法方法一方法二方法三 库加载问题静态库加载问题动态库的加载问题与位置无关码 C/C静态库下载方式 库的介绍 静态库&#xff1a;程序在编译链接的时…

[MoeCTF-2022]Sqlmap_boy

title:[MoeCTF 2022]Sqlmap_boy 查看网页源代码&#xff0c;得到提示 <!-- $sql select username,password from users where username".$username." && password".$password.";; --> 用万能密码绕过&#xff0c;用’"闭合 爆数据库…

Lambda表达式特点

Lambda 表达式是 Java 8 引入的一项重要特性&#xff0c;它们提供了一种更简洁的方式来表达匿名函数。Lambda 表达式允许你将一段代码传递给方法&#xff0c;而不是显式创建一个实现了接口的匿名内部类。Lambda 表达式通常用于实现单个抽象方法的接口&#xff08;即函数式接口&…