《Windows PE》6.1 重定位表

重定位表(relocation table)是在可执行文件或动态链接库(DLL)中用于指示系统在加载时对代码和数据进行重新定位的数据结构。在可执行文件或 DLL 中,代码和数据通常是使用相对地址进行引用的。当将可执行文件或 DLL 加载到内存中时,如果加载地址与文件中的基地址不匹配,就需要对代码和数据进行重新定位,以确保引用的地址正确。

本节必须掌握的知识点:

        重定位表

        重定位表的结构与解析

        重定位表的修改

6.1.1 重定位表

重定位表记录了需要进行重新定位的位置和相关的信息。在加载可执行文件或 DLL 时,系统会根据重定位表的信息来计算并更新代码和数据的地址,使其与实际加载地址相匹配。

重定位表通常由链接器在生成可执行文件或 DLL 时自动生成。它包含了需要进行重定位的节区、重定位类型和目标地址等信息。在加载时,操作系统会解析重定位表并根据其中的信息来进行重定位操作。

重定位表是可执行文件和 DLL 的重要组成部分,它确保了代码和数据在加载时能够正确地定位到正确的地址。对于编写和调试底层代码或需要手动进行加载的场景,了解和理解重定位表是很有帮助的。

代码重定位

PE文件头中的ImageBase字段为PE建议OS操作系统将程序导入内存中的首地址,在加载多任务时,如果申请的ImageBase出现冲突,OS操作系统会重新分配程序导入的首地址。

举例

●例一:

对于某个dll,若ImageBase为0x2000000,0x2002000指向IAT表,并在程序中出现以下调用IAT中函数的代码:

call dword ptr [0x2002000]

call dword ptr [0x2002004]

...

当OS没有按ImageBase给定的基址导入,而是导入0x4000000时,会出现:0x4002000指向IAT表,而代码没有改变,因此需要修正。

OS建一张表格,将涉及ImageBase的代码操作数(全局变量或函数地址)加入到该表格中并修正(即加上0x2000000)。

●例二:

重定位表用于在程序加载到内存中时,进行内存地址的修正。假设一个简单程序test.exe需要三个动态链接库dll(a.dll,b.dll,c.dll),假设test.exe的ImageBase为400000H,而a.dll、b.dll、c.dll的基址ImageBase均为10000000H。那么操作系统的加载程序在将test.exe加载进内存时,直接复制其程序到400000H开始的虚拟内存中,接着一一加载a.dll、b.dll、c.dll。

假设先加载a.dll,如果test.exe的ImageBase + SizeOfImage + 1000H不大于10000000H,则a.dll直接复制到10000000H开始的内存中;当b.dll加载时,虽然其基址也为10000000H,但是由于10000000H已经被a.dll占用,则b.dll需要重新分配基址,比如加载程序经过计算将其分配到12000000H的地址。c.dll同样经过计算将其加载到15000000H的地址。

但是b.dll和c.dll中有些地址是根据ImageBase固定的,被写死了的,而且是绝对地址不是相对偏移地址。比如b.dll中存在一个call 0x10034560,这是一个绝对地址,其相对于ImageBase的地址为δ = 0x10034560 – 0x10000000 = 0x34560H;而此时的内存中b.dll存在的地址是12000000H开始的内存,加载器分配的ImageBase和b.dll中原来默认的ImageBase(10000000H)相差了2000000H,因此该call的值也应该加上这个差值,被修正为0x12034560H,那么δ = 0x12034560H – 0x12000000H = 0x34560H则相对不变。如果call的地址不修正,会导致call指令跳转的地址不是实际要跳转的地址,获取不到正确的函数指令,程序则不能正常运行。

6.1.2 重定位表的结构与解析

IMAGE_BASE_RELOCATION 是 Windows PE 文件格式中的一个数据结构,用于指示系统在加载可执行文件或动态链接库(DLL)时对代码和数据进行重定位。它包含在可执行文件或 DLL 的重定位节区(.reloc)中。

IMAGE_BASE_RELOCATION 结构:

typedef struct _IMAGE_BASE_RELOCATION {

    DWORD VirtualAddress;   // 需要进行重定位的代码或数据的虚拟地址

    DWORD SizeOfBlock;      // 该重定位块的大小

// 具体的重定位项

WORD TypeOffset[1];

} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;

●IMAGE_BASE_RELOCATION 结构包含以下字段:

1.VirtualAddress:需要进行重定位的代码或数据的虚拟地址。这个地址是相对于基地址(加载时的起始地址)的偏移量,用于定位需要进行重定位的位置。

重定位项占用空间字节数的算法:

32位PE文件

Sum=2*n+4+4   ;2*n个地址+4字节的页面起始RVA+4字节的本页的重定位项个数

2表示每个重定位地址占用两个字节的空间,其中高四位为标记值,低12位为页内偏移地址。

64位PE文件

Sum=2*n+4+4   ;2*n个地址+4字节的页面起始RVA+4字节的本页的重定位项个数

8表示每个重定位地址占用四个字节的空间,其中高四位为标记值,低12位为页内偏移地址。

2.SizeOfBlock:该重定位块的大小,包括了所有的重定位项。它指示了该块的长度,以便在解析时快速定位到下一个重定位块。

该结构体有两个成员:一个是地址,一个是大小。一个重定位表的字节数由SizeOfBlock表示,(不同块的SizeOfBlock大小不一)。每一个块记录了1000H即4KB大小的内存中需要重定位信息的地址(一页大小)。

实际项数 = (SizeOfBlock - 8) / 2 ;8为sizeof IMAGE_BASE_RELOCATION 的字节数。

3.重定位项地址以VirtualAdress为该页的基址,偏移地址占两个字节(1000H最多需要12bit即可:0~FFFH)。所以两个字节的低12位为偏移地址,而4位就是一个标记,在32位PE文件中,当此标记为0011(3)时低12为才有效,否则该2个字节可能是为了对齐而产生的,并且为对齐而产生的字节其值全为0。

在64位系统中,这个标记值为10。由于重定位表的SizeOfBlock大小不确定,新的Block的重定位信息的结构体接着上一个Block,4字节对齐后开始,而当出现一个_IMAGE_BASE_RELOCATION结构体的值全为0时,表明重定位表结束。

这里只提出一部分比较短的Block信息,可以很明显地看到当需要重定位信息的记录长度是4Byte的倍数时,不存在高四位为0000的情况,当其不为4的倍数时,就有一个因对齐而产生的数据。

       ●SizeOfBlock高四位的含义

       如下表所示:

常量符号

含义

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值