PE文件格式学习(八):基址重定位表(BaseRelocationTable)

2024-04-27 19:32

本文主要是介绍PE文件格式学习(八):基址重定位表(BaseRelocationTable),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.简介

基址重定位表位于数据目录表中的第六个,它位于安全表的后面。

这个表的作用用来索引那些需要重定位的数据。程序的加载基址一般是0x400000,但是程序导入了众多的DLL,这些DLL的默认加载基址一般都是0x10000000,这就出现了一个问题,当第一个DLL加载到0x10000000处,第二个DLL就无法再加载到0x10000000处了,这时系统会自动分配一个加载基址给DLL文件。这就是需要重定位的根本原因,因为DLL的载入基址变了,有些绝对地址上的变量又不再正确了,需要进行重新定位。

重定位表中的项就是用来索引到需要重定位的数据处,通过一个公式计算出修复后的地址,数据就可以正确被访问了。

2.重定位表的解析

通过数据目录表查看到重定位表的RVA是5000h,转换成offset为0x1a00,我们找到0x1a00处:

我们对比重定位表的结构体来分析:

typedef struct _IMAGE_BASE_RELOCATION
{DWORD VirtualAddress;DWORD SizeOfBlock;WORD TypeOffset[1];
}IMAGE_BASE_RELOCATION;

需要首先进行说明的是,重定位表的RVA指向的位置是一个数组,里面的元素都是IMAGE_BASE_RELOCATION,每个IMAGE_BASE_RELOCATION只负责4KB大小分页内的重定位信息。因此结构中的VirtualAddress总是0x1000的倍数。

VirtualAddress:需要重定位的数据的RVA,这个值需要加上后面的TypeOffset的低12位才是需要重定位数据的RVA,这么说可能不好理解,我们用本文使用到的程序作为例子,这是它的一部分汇编代码:

Offset        HEX          Assembly
10001000      55           push ebp
10001001      8BEC         mov ebp,esp
10001003      6AFE         push 0xFFFFFFFF
10001005      68 10220010  push 0x10002210

程序的ImageBase是0x10000000,VirtualAddress是0x1000,后面要提到的TypeOffset的低12位是0x006,有如下公式成立:

需要重定位的数据位置 = ImageBase + VirtualAddress + TypeOffset低12= 0x10000000 + 0x1000 + 0x006

这里计算得到的最终需要重定位的数据地址是0x10001006,我们注意看上面的代码,0x10001005处是push 0x10002210,也就是说push后面的地址0x10002210需要进行重定位。

假设有一个dll实际加载到了0x72ab0000,它的ImageBase却是0x10000000,系统会通过下面的公式进行重定位

重定位后地址 = (真实加载基址-默认加载基址) + 需要进行重定位的地址= (0x72ab0000 - 0x10000000) + 0x10002210

SizeOfBlock:整个重定位表的大小,IMAGE_BASE_RELOCATION结构的总大小,对应上图中的0x118,实际上本文用到的程序有两个IMAGE_BASE_RELOCATION结构,它们的大小分别是0x118和0x24,合起来是0x13c,正好是数据目录表中标记的值。

TypeOffset:重定位的偏移,这个值加上IMAGE_BASE_RELOCATION中的VirtualAddress就是完整的RVA了,这个字段实际上并不属于IMAGE_BASE_RELOCATION结构体,但SizeOfBlock字段记录的大小包含了这个结构体,这个结构体通常有多个,按顺序进行排列,最后以0x0000作为结尾,结构体本身占2个字节,结构体如下:

struct
{WORD Offset:12; WORD Type:4; 
}TypeOffset;

Offset:低12位,上面介绍过,它跟VirtualAddress相加就是完整的重定位RVA


Type:重定位信息的类型,有如下类型:
#define IMAGE_REL_BASED_ABSOLUTE              0
#define IMAGE_REL_BASED_HIGH                  1
#define IMAGE_REL_BASED_LOW                   2
#define IMAGE_REL_BASED_HIGHLOW               3
#define IMAGE_REL_BASED_HIGHADJ               4
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_5    5
#define IMAGE_REL_BASED_RESERVED              6
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_7    7
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_8    8
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_9    9
#define IMAGE_REL_BASED_DIR64                 10
信息宏定义
0无重定位操作,用于4字节对齐IMAGE_REL_BASED_ABSOLUTE
1重定位指向位置的高2个字节需要被修正IMAGE_REL_BASED_HIGH
2重定位指向位置的低2个字节需要被修正IMAGE_REL_BASED_LOW
3重定位指向位置的全部4个字节需要被修正(绝大多数都是这种情况)IMAGE_REL_BASED_HIGHLOW
4需要两个TypeOffset配合完成索引IMAGE_REL_BASED_HIGHADJ
5IMAGE_REL_BASED_MACHINE_SPECIFIC_5
6保留IMAGE_REL_BASED_RESERVED
7IMAGE_REL_BASED_MACHINE_SPECIFIC_7
8IMAGE_REL_BASED_MACHINE_SPECIFIC_8
9IMAGE_REL_BASED_MACHINE_SPECIFIC_9
10重定位指向位置的8个字节需要被修正IMAGE_REL_BASED_DIR64

重定位表中记录的重定位信息的个数可以通过下面的公式进行计算:

重定位个数 = (SizeOfBlock - 8(IMAGE_BASE_RELOCATION的大小)) / 2(每个TypeOffset是2个字节)
总重定位个数 = 所有IMAGE_BASE_RELOCATION结构体相加后的重定位个数

因为数据目录表中记录的重定位表的大小是0x13c,而第一个IMAGE_BASE_RELOCATION只占用了0x118,所以应该还有其他的IMAGE_BASE_RELOCATION,通过0x1a00+0x118得到0x1b18,我们可以看到这个位置是另一个IMAGE_BASE_RELOCATION的起始,它的VirtualAddress是0x2000,它的SizeOfBlock是0x0024,通过将这两个IMAGE_BASE_RELOCATION的SizeOfBlock相加正好等于0x13c,通过计算第二个IMAGE_BASE_RELOCATION内的重定位个数是(0x24-8)/2=0xe,所以最终分析出来这个重定位表包括了两个IMAGE_BASE_RELOCATION,此程序一共有0x88+0xe个地方需要进行重定位修复。

这篇关于PE文件格式学习(八):基址重定位表(BaseRelocationTable)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/941341

相关文章

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

CSS Anchor Positioning重新定义锚点定位的时代来临(最新推荐)

《CSSAnchorPositioning重新定义锚点定位的时代来临(最新推荐)》CSSAnchorPositioning是一项仍在草案中的新特性,由Chrome125开始提供原生支持需... 目录 css Anchor Positioning:重新定义「锚定定位」的时代来了! 什么是 Anchor Pos

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen