目录 Table of Contents
10 基址重定位详解
什么是基址重定位
重定位就是你本来这个程序理论上要占据这个地址, 但是由于某种原因, 这个地址现在不能给你用, 你必须转移到别的地址, 这就需要基址重定位.
为什么需要基址重定位
可能你会问 windows 每个程序看自己都是有 4GB 内存的空间, 为什么会出现地址被别的程序占用了呢 ?
我们之前说过, 动态链接库自己是没有占据任何私有空间的, 都是寄生在应用程序的空间里面. 那么寄生在别人家里, 睡在哪里肯定就应该由别人说了算嘛. 基址重定位就是这么被需求的.
我们需要对程序中的哪些语句 (指令) 进行基址重定位
答案是--但凡是涉及到直接寻址的指令都需要进行重定位处理.
关于直接寻址, 这个在汇编语言里, 只要是在机器码中看到有地址的, 那就叫直接寻址.
我们回过头来看图, 发现以下指令需要对其进行重定位 :
inc dword ptr [10003000]
push dword ptr [10003000]
mov eax, dword ptr [10003000]
dec dword ptr [10003000]
push dword ptr [10003000]
mov eax, dword ptr [10003000]
jmp dword ptr [10002000]
有些朋友可能会问, 类似于 call 1000100C
的指令, 为什么后边显示的是 call+地址
, 而机器码却不包含地址信息呢 ? 这和 call 的原理有关.
系统对一条指令进行重定位需要哪些信息
还是刚才那个图片, 我们知道上面的指令需要重定位, 现在假设重定位后的基址从 10000000H 变为 20000000H, 那么类似这样的语句 : inc dword ptr [10003000]
应该变成 inc dword [20003000]
- 注意, 重定位的算法我们可以总结为 : 将直接寻址指令中的双字地址加上模块的实际装入地址与模块建议装入地址之差
从上面的信息我们可以看到, 进行重定位需要三个因素 :
-
需要修正的地址 (10003000H)
-
建议装入的地址 (10003000H)
-
实际装入的地址 (20003000H)
这些信息哪些应该被保存在重定位表中
我们可以发现 :
-
建议装入的地址在 PE 文件头中已经定义了
-
实际装入的地址在没有被装载器装入的时候, 我们根本就没办法知道, 也就是这个只有装载器知道
因此, 我们可以得到的结论是 : PE 文件的重定位表 (Base Relocation Table) 中保存的就是文件中所有需要进行重定位修正的代码的地址.
基址重定位表
IMAGE_BASE_RELOCATION struct
VirtualAddress DWORD ? ; 重定位数据开始的 RVA 地址
SizeOfBlock DWORD ? ; 冲定位块的长度
TypeOffset WORD ? ; 重定项位数组
IMAGE_BASE_RELOCATION ends
VirualAddress 是 Base Relocation Table 的位置, 它是一个 RVA 值
SizeOfBlock 是 Base Relocation Table 的大小
TypeOffset 是一个数组, 数组每项大小为两个字节 (16 位), 它由高 4 位和低 12 位组成, 高 4 位代表重定位类型, 更多信息请看基址重定位类型; 低 12 位是重定位地址, 它与 VirtualAddress 相加就是指向 PE 映像中需要修改的那个代码的地址
基址重定位类型
Constant | Value 类型码 | 描述 |
---|---|---|
IMAGE_REL_BASED_ABSOLUTE | 0 | 基址重定位将被跳过, 此类型可用于填充区块. 使区块按照 32 位对齐, 位置为 0. |
IMAGE_REL_BASED_HIGH | 1 | 高 16 位必须用于偏移量所指高字 16 位 |
IMAGE_REL_BASED_LOW | 2 | 低 16 位必须应用于偏移量所指低 16 位 |
...... | ...... | ...... |
后面的自行查阅 MSDN : https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
这里说下常见的, 来自第四版 <加密与解密>
类型 | winnt.h 里的预定义值 | 含义 |
---|---|---|
0 | IMAGE_REL_BASED_ABSOLUTE | 没有具体定义, 只是为了让每个段 4 字节对齐 |
3 | IMAGE_REL_BASED_HIGHLOW | 重定位指向的整个地址都需要修正, 实际上大部分情况下都是这样的 |
10 | IMAGE_REL_BASED_DIR64 | 出现在 64 位 PE 文件中, 对指向的整个地址进行修正 |