- 1.重定位表的作用
- 2.重定位表的结构与解析
- 3.重定位表的修改
- 4.作者答疑
重定位表(Relocation Table)用于在程序加载到内存中时,进行内存地址的修正。一个简单程序test.exe需要三个动态链接库dll(a.dll,b.dll,c.dll),假设test.exe的ImageBase为400000H,而a.dll、b.dll、c.dll的基址ImageBase均为1000000H。那么操作系统的加载程序在将test.exe加载进内存时,直接复制其程序到400000H开始的虚拟内存中,接着一一加载a.dll、b.dll、c.dll:假设先加载a.dll,如果test.exe的ImageBase + SizeOfImage + 1000H不大于1000000H,则a.dll直接复制到1000000H开始的内存中;当b.dll加载时,虽然其基址也为1000000H,但是由于1000000H已经被a.dll占用,则b.dll需要重新分配基址,比如加载程序经过计算将其分配到1200000H的地址,c.dll同样经过计算将其加载到150000H的地址。
但是b.dll和c.dll中有些地址是根据ImageBase固定的,被写死了的,而且是绝对地址不是相对偏移地址。比如b.dll中存在一个call 0X01034560,这是一个绝对地址,其相对于ImageBase的地址为δ = 0X01034560 - 0X01000000 = 0X34560H;而此时的内存中b.dll存在的地址是1200000H开始的内存,加载器分配的ImageBase和b.dll中原来默认的ImageBase(1000000H)相差了200000H,因此该call的值也应该加上这个差值,被修正为0X01234560H,那么δ = 0X01234560H - 0X01200000H = 0X34560H则相对不变。否则call的地址不修正,会导致call指令跳转的地址不是实际要跳转的地址,获取不到正确的函数指令,程序则不能正常运行。
2.重定位表的结构与解析在系统中的定义,如下所示:
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;//4字节
DWORD SizeOfBlock;//4字节
// WORD TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
该结构体有两个成员:一个是地址,一个是大小。一个重定位表的字节数由SizeOfBlock表示,(不同块的SizeOfBlock大小不一)。每一个块记录了1000H即4KB大小的内存中需要重定位信息的地址(一页大小),这些地址以VirtualAdress为该页的基址,偏移地址占两个字节(1000H最多需要12bit即可:0~FFFH)。所以两个字节的低12位为偏移地址,而高4位就是一个标记,当此标记为0011(3)时低12为才有效,否则该2个字节可能是为了对齐而产生的,并且为对齐而产生的字节其值全为0,在64位系统中,这个值为10。由于重定位表的SizeOfBlock大小不确定,新的Block的重定位信息的结构体接着上一个Block,4字节对齐后开始,而当出现一个_IMAGE_BASE_RELOCATION结构体的值全为0时,表明重定位表结束。 这里只提出一部分比较短的Block信息,可以很明显地看到当需要重定位信息的记录长度是4Byte的倍数时,不存在高四位为0000的情况,当其不为4的倍数时,就有一个因对齐而产生的数据。 在SizeBlock后面紧跟着的就是一个TypeOffset数组,一个大小是2字节,其中高4位代表修正的类型,低12位是修正的偏移。它的大小与VirtualAddress相加就是要修正的RVA地址。当出现一个_IMAGE_BASE_RELOCATION结构体的值全为0时,表明重定位表结束。
3.重定位表的修改如果需要编译PE文件,并在PE文件中,增加部分代码,建议增加新的一段,这样从内存排序来讲,新的段将在内存上分配在虚拟地址的高位,这样我们可以通过增加重定位表的大小,然后在重定位表的末尾增加需要的重定位地址。
4.作者答疑如有疑问,请留言。
提示: 作者知了-联系方式1 提示: 作者知了-联系方式2