基址重定位表

一、PE重定位

PE文件在重定位过程中会用到基址重定位表(Base Relocation Table)。

向进程的虚拟内存加载PE文件(EXE/DLL/SYS)时,文件会被加载到PE头的ImageBase所指的地址处。若加载的是dll(sys)文件,且在ImageBase位置处已经加载了其他的dll(sys)文件,那么PE装载器就会将其加载到其他未被占用的空间。

使用SDK或Visual C++创建PE文件时,EXE默认的ImageBase为00400000,DLL默认的ImageBase为10000000。此外使用DDK(驱动开发工具包)创建SYS文件默认的ImageBase为10000

DLL/SYS

A.DLL被加载到TEST.EXE进程的10000000地址处。此后,B.DLL试图加载到相同地址时,PE装载器将B.DLL加载到另一个尚未被占用的地址(3C000000)处。
在这里插入图片描述

EXE

创建好进程后,EXE文件会首先加载到内存,所以在EXE中无须考虑重定位的问题。但是windows中引入了ASLR安全机制,每次运行EXE文件都会被加载到随机地址,这样大大增强了系统安全性。
我们分别运行3次ConsoleApplication4.exe(32位)时截图,可以明显发现,每次运行时程序都被加载到不同的地址。

三次运行结果发现,入口地址均不一样。但是这是建立在重启电脑的前提下,如果不重启电脑,每次执行的结果都是一致的。
Windows系统对已加载的exe基地址进行了缓存优化。若exe文件未修改且系统未重启,基地址可能被复用以减少性能开销

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ASLR机制也适用于DLL/SYS文件。对于各OS的主要系统DLL,微软会根据不同版本分别赋予不同的ImageBase地址。同一系统的kernel32.dll、user32.dll等会被加载到自身固有的ImageBase,所以,系统的DLL实际不会发生重定位问题。

二、PE重定位时执行的操作

接下来我们写一个小程序ConsoleApplication4.exe为例,看看PE重定位到底发生了什么。使用OllyDbg运行我们的程序。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

我们的程序在ASLR机制的作用下,被加载到00500000地址处,从图中指令可以看到,方框中进程的内存地址与小辣椒对应的文件数据并不统一,这是为什么呢?像这种使硬编码在程序中的内存地址随当前加载地址变化而变化的处理过程就是PE重定位。

无法加载到ImageBase地址时,若未进行过PE重定位处理,应用程序就不能正常运行(因发生“内存地址引用错误”,程序异常终止)。


我们在对比以上程序的内存地址与硬编码地址后,归纳整理如下

文件(ImageBase:00400000)进程内存(加载地址:00500000)
0040316000503160
0040315C0050315C
0040315800503158
0040315400503154
0040315000503150
0040314C0050314C
0040317800503178

硬编码地址以ImageBase为基准。生成ConsoleApplication4.exe文件时,由于无法预测程序被实际加载到哪个地址,所以记录硬编码地址时以ImageBase为基准。但是在运行的瞬间,经过PE重定位后,这些地址全部以加载地址为基准变换,最后程序得以正常执行而不发生错误。


三、PE重定位操作原理

Windows的PE装载器进行PE重定位处理时,基本的操作原理很简单。

PE重定位的基本操作原理
- 在应用程序中查找硬编码的地址位置
- 读取值后,减去ImageBase
- 加上实际加载地址

其中最关键的是查找硬编码地址的位置。查找过程中会用到PE文件内部的Relocation Table(重定位表),它是记录硬编码地址偏移(位置)的列表(重定位表是在PE文件构建过程中提供的)。通过重定位表查找,其实就是指根据PE头的“基址重定位表”项进行的查找。

基址重定位表

基址重定位表地址位于PE头的DataDirectory数组的第六个元素(数组索引为5)
在这里插入图片描述
如图基址重定位表的地址为RVA 5000,计算得到文件偏移为 5000 - 5000 + 2200 = 2200
在这里插入图片描述

在这里插入图片描述

IMAGE_BASE_RELOCATION结构体

基址重定位表中罗列了硬编码地址的偏移。读取这张表就能获取准确的硬编码地址偏移。基址重定位表是IMAGE_BASE_RELOCATION结构体数组。
在这里插入图片描述
IMAGE_BASE_RELOCATION结构体的第一个成员为VirtualAddress,它是一个基准地址,实际是RVA值。第二个成员为SizeOfBlock,指重定位块的大小。最后一项TypeOffset数组不是结构体成员,而是以注释形式存在的,表示在该结构体之下会出现WORD类型的数组,并且该数组元素的值就是硬编码在程序中的地址偏移。

基址重定位表的分析方法

在这里插入图片描述
基址重定位表的部分内容

文件偏移RVA数据注释
2200500000001000VirtualAddress
2204500400000160SizeOfBlock
220850083006TypeOffset
220A500A300BTypeOffset
220C500C3013TypeOffset
220E500E301ETypeOffset

由IMAGE_BASE_RELOCATION结构体的定义可知,VirtualAddress成员的值为1000,SizeOfBlock成员的值为160。也就是说,TypeOffset数组的基准地址(起始地址)为RVA 1000,块的总大小为160.块的末端显示为0.TypeOffset值为2个字节大小,是由4位的Type与12位的Offset合成的。比如,TypeOffset值为3006,解析如下

类型(4位)偏移(12位)
3006

高4位用作Type,PE文件中常见的值位3(IMAGE_REL_BASED_HIGHLOW),64位的PE+文件中常见值为A(IMAGE_REL_BASED_DIR64)

在恶意代码中正常修改文件代码后,有时要修改指向相应区域的重定位表(为了略去PE装载器的重定位过程,常常把Type值修改为0(IMAGE_REL_BASED_ABSOLUTE))

TypeOffset的低12位是真正的位移,该位移值基于VirtualAddress的偏移。所以程序中硬编码地址的偏移使用下面等式换算
VirtualSize(1000) + Offset(006) = 1006(RVA)

练习

现在我们可以结合之前od与小辣椒的数据进行分析

地址值文件偏移对应RVATypeOffset
0040316006BE12BE32BE
0040315C06C412C432C4
0040315806CA12CA32CA

在这里插入图片描述
在这里插入图片描述

四、ASLR机制

基本原理

地址空间布局随机化(Address Space Layout Randomization,ASLR)是一种通过随机化关键内存区域的基址来防御内存攻击的安全机制。其核心思想是打破攻击者对内存布局的预测能力,例如栈、堆、共享库和可执行模块的地址不再是固定值,而是每次程序启动时动态分配。

visual studio中可以通过属性 – 链接器 – 高级 – 随机基址。进行ASLR属性的开启关闭。

在这里插入图片描述
通过查看NT头 – Optional Header – DllCharacteristics 中值为 0040代表开启ASLR
在这里插入图片描述

工作流程

1. 静态随机化
在程序加载阶段,操作系统为以下区域分配随机基址:

  1. 主可执行模块(如.exe或ELF文件)
  2. 动态链接库(DLL/.so)
  3. 栈空间
  4. 堆空间

基址=默认基址+R×页面大小

其中R为随机数,页面大小通常为4KB或2MB。

2. 动态随机化
运行时通过以下方式增强随机性:

  1. 堆内存分配时添加随机偏移(如Windows的HeapAlloc)
  2. 栈帧地址随机化(通过插入随机填充字节)
  3. 共享库重定位(如Linux的mmap随机化)

实现机制

1. 操作系统支持
- Windows:自Vista起全面支持ASLR,要求程序启用/DYNAMICBASE链接选项
- Linux:通过内核参数kernel.randomize_va_space控制(0关闭/1部分开启/2完全开启)

2. 硬件协同
依赖内存管理单元(MMU)的分页机制,将虚拟地址随机映射到物理地址。例如:

// Linux内核代码片段(简化)
unsigned long random_offset = get_random_int() & 0x00FFFFFF;
load_address = default_base | random_offset;

3. 安全增强

  • High Entropy ASLR(Windows 8+):将随机熵从8位提升至24位
  • PIE(Position-Independent Executable):使可执行文件自身支持重定位

优缺点分析

优势局限性
增加漏洞利用难度无法防御信息泄露攻击
与其他机制(如DEP)形成纵深防御可能增加内存碎片
对性能影响通常小于1%需程序/编译器支持(如PIE)

绕过方法示例

  1. 通过内存泄露获取基址
  2. 暴力破解低熵ASLR(如早期Android实现)
  3. 利用未随机化区域(如部分JIT编译代码)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值