PE文件(十)重定位表

news2024/11/14 14:29:41

重定位表的引入

程序加载过程

在win32下,每一个PE文件(其可能由多个子PE文件组成)在运行时,操作系统会给分配一个独立的4GB虚拟内存,内存地址从0x00000000到0xFFFFFFFF。其中低2G为用户程序空间,高2G为操作系统内核空间。并且操作系统会将该文件中数据拉伸成内存中数据,从ImageBase开始,分配SizeOfImage大小空间

当一个主PE文件由很多个子PE文件组成,当我们运行主PE文件时,所有的PE文件共享操作系统分配的一个4GB虚拟空间。如下图我们用OD打开ipmsg.exe程序去查看其模块,可以发现,ipmsg.exe由很多其他PE文件组成,这些文件也叫做模块

在上图中,各PE文件的base也就是其在内存中的起始位置,size也就是其在内存中大小

上图是一个PE文件在4GB虚拟内存中的分布,它由多个PE文件组成。从ImageBase(0x00400000)开始,分配空间SizeOfImage(0x3D000)大小

之后装载需要用到的.dll:把ws2help.dll装载到从ImageBase(0x71A10000)开始,分配空间大小为SizeofImage(0x8000)。其他.dll也是如此

最后把EIP指向EOP(AddressOfEntryPoint),这个程序就可以执行了

注意:我们可以自定义每个PE文件的sizeofimage,具体流程是:打开VC->右键你的项目->setting->选择Link->Category设置为Output->在Base address选项中就可以自定义ImageBase了,之后这个程序编译以后,ImageBase就变成了我们所修改的了

程序编译时的问题

问题一:DLL装载地址冲突

一般情况下一个PE文件自身的子.exe文件的ImageBase不会和别的子.exe文件的ImageBase发生冲突

但是默认情况下DLL的ImageBase为0x10000000,因此如果一个PE文件的多个DLL没有合理的修改分配装载起始地址,就可能出现其ImageBase都是同一个地址,造成装载冲突

注意:如果一个DLL在装载到虚拟内存中时,操作系统发现其他DLL已经占用这块空间了,那么这个DLL会依据模块对齐粒度,往后找空余的空间存入,此时,.dll便有了其内存空间,这个过程,本人称作内存再分配。在程序每次运行时,内存再分配的情况都是不一样的

模块对齐粒度:和结构体的字节对齐一样是为了提高搜索的速度(空间换时间),模块间地址也是要对齐的。模块对齐粒度默认 为0x10000,也就是64K

问题二:编译后的绝对地址

一个.dll或.exePE文件中的全局变量,在程序编译完成后,其全局变量的绝对地址就写入PE文件了。如以下文件中a(人为的全局变量)和%d(系统的全局变量),编译完后地址值都是不变的。

 

假设如果这个PE文件在装载时,某DLL装载地址冲突,系统会对该.dll文件进行再分配内存空间。由于这个.dll文件的全局变量地址在编译完成后就不再改变,当程序执行时,程序会按这个绝对地址去寻找全局变量使用。而该.dll文件由于装载时再分配内存,就会出现找不到这个全局变量的问题。

不单是全局变量,.DLL中对外提供的函数的地址在编译完后也是不再改变的,而如果此时DLL装载时其分配内存空间发生了改变了,通过这些不变的函数地址也找不到需要的函数了

重定位表引入

所以如果一个PE文件出现了内存装载冲突的情况,那么就需要重定位表,来记录下来,有哪些地方的数据需要做修改、重新定位,保证在内存再分配后,操作系统能正确找到这些数据

比如再问题二中:这个PE文件各子PE文件没有按照其本来ImageBase去装载,而是进行了内存再分配。那么我们写入的全局变量a的存储地址就会发生变化,但是由于硬编码已经生成:A1 30 4A 42 00,那么重定位表就会把30 4A 42 00这个数据的地址记下来,等到运行时操作系统会根据重定位表找到这个数据,做一个重定位修改,即把0x00424a30这个绝对地址修改成它现在所在的绝对地址,保证全局变量a可以被准确找到,修改的操作由操作系统进行负责。

因为一个PE文件的.exe子PE文件一般只有一个,且是最先装载,所以装载位置和其ImageBase是一致的,不需要内存再分配,而.dll子PE文件有很多,所有操作系统需要考虑其装载的位置是不是预期的位置,如果不是,.dll子PE文件就需要提供重定位表

重定位表的位置

找到可选PE头中的最后一个成员数据目录项(有16个元素的结构体数组):找到第6个结构体,就是重定位表的数据目录

下图便是重定位表的位置:

根据重定位表数据目录的VirtualAddress,便可以获取重定位表的地址

重定位表结构

typedef struct _IMAGE_BASE_RELOCATION

{

DWORD VirtualAddress;

DWORD SizeOfBlock;

//在这里还有一堆未知的数据

} IMAGE_BASE_RELOCATION;

typedef IMAGE_BASE_RELOCATION ,* PIMAGE_BASE_RELOCATION;

该结构体虽然叫做重定位表结构体,但实际上本人认为它叫做块结构体更合适

这是因为一个完整重定位表是由多个块组成的,最后一个块的VirtualAddress和SizeOfBlock都是0x00000000,表示重定位表结束。如下图便是一个完整的重定位表:

1.VirtualAddress

宽度为4字节

由于4GB虚拟内存地址需要32位即4字节的数才能完整表示,所以当有10000个地方要修改,就需要记录下这10000个地方的地址,一个地址4字节,共需大小10000 * 4 = 40000字节空间,如此记录,一张表所占内存大小就过大了

因此操作系统会把一个PE文件分页,内存中一个页的大小为0x1000字节,相当于把文件分成了一小页一小页的。

那么如果在一页中有需要重定位的地方,重定位表就会给这个页安排一个块,这个块的VirtualAddress存储了此页的偏移起始地址(RVA)。由于一页的大小只有0x1000字节(4096),所以用12位二进制数就可以表示的下4096个地址,此时记录地址所需要的空间就大大减少了。由于内存对齐的缘故,所以把这个值用16位存放。多出来的高4位可以用来表示其他的含义,低12位表示需要修改的地方相对于所在页的偏移地址故具体项占16位,

2.SizeOfBlock

表示每个块的大小,单位为字节

3.具体项

在结构体中未知的一堆数据中,每两个字节叫一个具体项。

具体项的高4位表示类型:值为3,即0011。一个块中有多少个高4位为0011的具体项,就表示这个块当中有多少个地方需要做重定位修改

当具体项的值为0时,说明这个数据项的2个字节的数据用来做数据对齐用,可以不用修改。因此我们只需要关注高4位值为3的具体项就可以了。

一块中一共有多少个具体项用(此块的SizeofBlock - 4 - 4 )/ 2进行计算

具体项的低12位的值表示要修改的地方相对于所在块的VirtualAddress(也是项所在页)的偏移地址,该值加上该块的VirtualAddress的结果便是要修改的地方的在内存的绝对地址,这个地址上的数据则需要修改做重定位。

综上所述:一页中如果有要重定位的地方,重定位表给此页安排一块(一块对应一页)。此块的VirtualAddress存储此页的起始地址;具体项占16位,高4位表示类型,低12位表示要修改的地方相对于所在页的偏移地址。

页、块、节的关系

一个PE文件(可执行程序)运行时,装入虚拟内存时操作系统会对程序进行分页。重定位表会根据页进行分块。但程序中的节跟分页和分块没有任何关系

我们用LordPE打开一个有重定位表的PE文件,查看重定位表

发现:这个重定位表分了很多块,第175块中记录的是偏移地址为0xAF000的页中要修改重定位的地方,这些要修改的地方在.text节中。第176块中记录的是偏移地址为0xB000的页中要修改重定位的地方,这些要修改的地方在.data节中

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

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

相关文章

【Linux】进程间通信——消息队列和信号量

目录 消息队列(message queue) 信号量(Semaphore) system V版本的进程间通信方式有三种:共享内存,消息队列和信号量。之前我们已经说了共享内存,那么我们来看一下消息队列和信号量以及它们之间…

【鸿蒙学习笔记】位置设置・position・绝对定位

官方文档:位置设置 目录标题 position:绝对定位,确定子组件相对父组件的位置。 position:绝对定位,确定子组件相对父组件的位置。 正→ ↓ Entry Component struct Loc_position {State message: string Hello Wor…

汇编语言程序设计-8-汇编语言快速查阅

8. 汇编语言快速查阅 文章目录 8. 汇编语言快速查阅常用资料寄存器含义标志寄存器的含义Debug的使用汇编语法 本章列出一些需要经常查阅的知识点。 常用资料 参考视频:烟台大学贺利坚老师的网课《汇编语言程序设计系列专题》,或者是B站《汇编语言程序设计…

vue学习day08-v-model详解、sync修饰符、ref和$refs获取dom组件、Vue异步更新和$nextTick

25、v-model详解 (1)v-model原理 1)原理: v-model本质上是一个语法糖,比如:在应用于输入框时,就是value属性与input事件的合写。 2)作用 ①数据变,视图变 ②视图变&#xff0c…

【 C++ 】详解 (类和对象) 继承

继承的概念及定义 继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象 程序设计的层次结构…

【Linux】Linux的账号和用户组

管理员的工作中,相当重要的一环就是【管理账号】。 因为整个系统都是你在管理,并且所有一般用户的账号申请,都必须要通过你的协助才行,所以你就必须要了解一下如何管理好一个服务器主机的账号。 在管理Linux主机的账号时&#xff…

Python应用开发——30天学习Streamlit Python包进行APP的构建(15):优化性能并为应用程序添加状态

Caching and state 优化性能并为应用程序添加状态! Caching 缓存 Streamlit 为数据和全局资源提供了强大的缓存原语。即使从网络加载数据、处理大型数据集或执行昂贵的计算,它们也能让您的应用程序保持高性能。 本页仅包含有关 st.cache_data API 的信息。如需深入了解缓…

AG32 的MCU与FPGA的主频可以达到568MHz吗

Customers: AG32/ AGRV2K 这个芯片主频和定时器最高速度是多少?用户期望 CPLD计时器功能0.1ns以下。 AGM RE: CPLD做不到 0.1ns的速率,这个需要10G以上的时钟。 那AGRV2K最高多少MHz呢? 一般200MHZ比较容易实现。 进一步说明&#xff1…

智慧校园服务监控功能

智慧校园系统中的服务监控功能,扮演着维护整个校园数字化生态系统稳定与高效运作的重要角色。它如同一位全天候的守护者,通过实时跟踪、分析并响应系统各层面的运行状况,确保教学、管理等核心业务流程的顺畅进行。 服务监控功能覆盖了智慧校园…

自动控制——变速积分的PID控制

变速积分的PID控制 PID控制(Proportional-Integral-Derivative Control)是工业控制中最常用的控制算法之一。标准的PID控制器由比例(P)、积分(I)和微分(D)三个部分组成,…

连锁直营店小程序赋能多店如何管理

如商超便利店卖货线下场景,也有不少品牌以同城多店和多地开店经营为主,获取店铺周围客户和散流,如今线上重要性凸显,品牌电商发展是经营的重要方式之一,也是完善同城和外地客户随时便捷消费的方式之一。 多个门店管理…

Js 前置,后置补零的原生方法与补字符串 padStart及padEnd

在工作中,遇到了需要将不满八位的一个字符串进行后补0的操作,所以就在网上学习了关于js原生补充字符串的方法,然后用这篇博客记录下来。 目录 前置补充字符串 String.prototype.padStart() 后置补充字符串String.prototype.padEnd() 前置补…

OpenGL笔记十之Shader类的封装

OpenGL笔记十之Shader类的封装 —— 2024-07-10 晚上 bilibili赵新政老师的教程看后笔记 code review! 文章目录 OpenGL笔记十之Shader类的封装1.运行2.目录结构3.main.cpp4.application4.1.CMakeLists.txt4.2.Application.h4.3.Application.cpp 5.assets5.1.shaders&#xf…

虚拟机:VMware功能,安装与使用

目录 一、虚拟机介绍 二、VMware 1.介绍 2.安装 (1)根据提示按步骤安装​编辑 (2)更改软件的安装地址​编辑 (3)根据自己的需求选择是否需要软件更新​编辑 (4)根据需求选择…

20240715 每日AI必读资讯

🌐 代号“ 草莓 ”,OpenAI 被曝研发新项目:将 AI 推理能力提至新高度 - OpenAI 公司被曝正在研发代号为“ 草莓 ”的全新项目,进一步延伸去年 11 月宣布的 Q* 项目,不断提高 AI 推理能力,让其更接近人类的…

27.数码管的驱动,使用74HC595移位寄存器芯片

PS:升腾A7pro系列FPGA没有数码管外设,因此以AC620FPGA为例展开实验。 (1)共阳极数码管和共阴极数码管示意图: AC620中的数码管属于共阳极数码管,段选端口(dp,g,f,e,d,c,b,a)低电平即可点亮led。人眼的视觉…

Flink CDC 同步表至Paimon 写数据流程,write算子和commit算子。

Flink CDC 同步表至Paimon 写数据流程,write算子和commit算子。(未吃透版) 流程图 一般基本flink cdc 任务同步数据至paimon表时包含3个算子,source、write、global commit。 source端一般是flink connector实现的连接源端进行获取数据的过程,本文探究的是 source算子获…

算法学习笔记(8.6)-编辑距离问题

目录 Question: 动态规划思路: 第一步:思考每轮的决策,定义状态,从而得到dp表 第二步:找出最优子结构,进而推导出状态转移方程 第三步:确定边界条件和状态转移顺序 代码实现&#xf…

BUUCTF逆向wp [FlareOn4]login

按老规矩先查壳&#xff0c;但本题是html文件&#xff0c;查壳会报错 在网上查了一下&#xff0c;可以用vscode查看源代码&#xff0c;我们用VS code打开。 <!DOCTYPE Html /> <html> <head> <title>FLARE On 2017</title> </head> <…

d3dcompiler_47.dll缺失怎么修复,一步步分析d3dcompiler_47.dll文件

d3dcompiler_47.dll缺失怎么修复&#xff1f;快速教大家解决出现d3dcompiler_47.dll问题的方法&#xff0c;一步步教大家快速有效的将丢失的d3dcompiler_47.dll如何修复。 一步步修复d3dcompiler_47.dll分析 1. 重新安装受影响的程序 如果是特定程序报告缺少d3dcompiler_47.d…