PE 重定位简述
当 PE 文件被加载进虚拟内存却并非加载到 PE 头所指定的 ImageBase 处时(如 ASLR 机制),我们就说发生了 PE 重定位。比如说我们某一个 PE 文件的 ImageBase 为 0x400000,然而加载时却被加载到了 0xDC0000,这就是发生了重定位。
重定位不是简简单单的更改了映像基址这么简单,文件中可能存在一些硬编码地址,这些硬编码地址是和 PE 头指定的 ImageBase 相适应的。一旦发生了重定位,内存中的内存基址就不再和这些硬编码的地址相适应,运行时就会出现问题。
举个例子,PE 头中的 ImageBase 是 0x400000,而代码段中有这样一句指令 call dword ptr ds:[0x4003C0]
,它的十六进制机器码为 FF 15 C0 03 40 00
,这里 0x4003C0 就是硬编码的地址,它是写死在磁盘的文件中的。当程序被加载到 0x400000 时,这句指令将正常工作;而当程序被加载到了 0xDC0000 时,如果没有经过重定位修复,这句指令很明显将会执行出错,而重定位之后,内存中的这句指令将变成 call dword ptr ds:[0xDC03C0]
,可以正常执行。
因此,重定位的主要工作是修复这些硬编码的地址,使之与新的映像基址相适应。然而程序中很有可能存在大量的硬编码地址,我们需要修改这些地址,首先就得找到这些地址。要找到这些地址,在装载时再进行扫描分析是不可行的,因为我们无法区分这是一个硬编码的地址还是一个普通的数据。正确的做法是在程序编译链接时把每一个硬编码地址所在位置