【2021.01.15】重定位表

什么是重定位表?为什么要有重定位表?

  1. 如上图 A.DLL 和 B.DLL 中某个或多个的全局变量编译时可能是相同的内存地址。
  2. 如果 A.DLL 先行加载,其中的某个全局变量抢占到了 0x00410000 这个内存地址。
  3. B.DLL 因为后加载的原因,是从 0x00420000 处开始展开。此时,B.DLL 中如果有全局变量的地址也是 0x00410000 这个内存地址,就会出问题。
  4. 因为在调用 B.DLL 中某个全局变量的时候,如 0x00410000 地址的变量,但因为 B.DLL 是从 0x00420000处开始展开的,所以就无法调用。
  5. 那么这个时候就需要有一张表,记录并修改冲突的项目,例如把 B.DLL 中的 0x00410000 改为 0x00420000,那么就能正常使用了。

重定位表的位置

PE结构图:IMAGE_OPTIONAL_HEADER->DataDirectory 中的 IMAGE_DIRECTORY_ENTRY_BASERELOC 成员,就是重定位表。

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;        //以字节为单位,它有多大代表一个重定位块有多大
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

什么是重定位块?

一个PE文件中需要修正的地方是有很多的,需要分成很多块来记录。

根据什么来设计为一块一块的?

  1. 内存以 4KB 为单位,也就是在物理内存上,每个内存的大小划分是 4KB,4KB为一个物理页,重定位表也是如此设计。
  2. 一个物理页创建一张重定位表,每张重定位表只负责修复当前物理页上的相关内容,与其他物理页不影响。

如何确定重定位表结束?

直到出现连续 8 个为 00 的字节,代表当前进程重定位表结束。

  • 每个物理页(4KB)重定位表中的地址,在4KB中的偏移需要多少个二进制位才能找到偏移?2的12次方 = 4KB
  • 物理页只有 4KB,如果想找到物理页中的任何一个地址,只需要 12 个二进制位就够了,但是占用了 16 个位。
  • 也就是说,虽然重定位表中真正要修正的数据每个是 2 字节(16 个二进制位),但是真正使用到的只有 16 个二进制位中的 12 个二进制位。
  • 16 个二进制位的高 4 位挪作他用(图中标红的部分),当操作系统真正要修复某个位置的时候,先判断高 4 位。
  • 只有当高 4 位的值等于 3 的时候,才意味着 VirtualAddress + 低12位 才是真正要修复的位置。

猜你喜欢

转载自blog.csdn.net/qq_18120361/article/details/112646463