Chinese:
1、基址重定位就是本来程序理论上要占据这个地址,但是由于某种原因,这个地址现在不能让你霸占,因此必须转移到其他地址。
2、一般来说涉及到直接寻址的指令都需要进行重定位处理。
:6AE81890 A16040E86A mov eax, dword ptr [6AE84060] :6AE818A1 03054040E86A add eax, dword ptr [6AE84040] :00402F03 A01CBB4000 mov al, byte ptr [0040BB1C]
类似上面的这些代码,都是需要重定位的,比如我需要把基址改成10000000,那么以上的代码就要替换成1AE84060, 1AE84040, 1040BB1C这样,但是总需要一个地方用来记录需要重定位的地址信息,这个地方就是 重定位表(Base Relocation Table)了。
3、基址重定位表结构
IMAGE_BASE_RELOCATION STRUCT VirtualAddress DWORD ? ;重定位数据开始的RVA地址 SizeOfBlock DWORD ? ;重定位块的长度 TypeOffset WORD ? ;重定项位数组 IMAGE_BASE_RELOCATION ENDS
[VirtualAddress]
重定位表的位置,RVA
[SizeOfBlock]
重定位表的大小
[TypeOffset]
该数组每项大小为两个字节(16位),高4位代表重定位类型(一般用不到),低12位是重定位地址,它与VirtualAddress相加即为指向PE映像中需要修改的那个代码的地址。
高4位类型码:
IMAGE_REL_BASED_ABSOLUTE 使块按照32位对其,位置为0
IMAGE_REL_BASED_HIGH 高16位必须应用于偏移量所指高字16位
IMAGE_REL_BASED_LOW 低16位必须应用于偏移量所指低字16位
IMAGE_REL_BASED_HIGHLOW 全部32位应用于所有32位
IMAGE_REL_BASED_HIGHADJ 需要32位,高16位位于偏移量,低16位位于下一个偏移量数组元素,组合为一个带符号数,加上32位的一个数,然后加上8000然后把高16位保存在偏移量的16位域内。
通过一个实例查找基址重定位信息:
(1)通过PEInfo找到Base Directory中的基址重定位表的RVA
(2) 找到0x7000所在的区块,一般都是.reloc区块,该区块对应的物理地址(ROffset)为0x1E00
(3) 用16进制编译器打开该文件,找到0x1E00这个地址,这个地址就是Base Relocation Table的位置
(4) 前4个字节0x1000就是VirtualAddress,接着的4个字节0x0128就是长度SizeOfBlock,那么我们其实就可以算出重定位的数量:(0128h - 8h) / 2 = 90h 也就是说记录了90个重定位项。每个重定位项占一个字,我们先看第一个0x3009,高4位是3,代表就是一个32位程序,低12位是009,加上VirtualAddress就是PE映像中要重定位的地址了,相加为0x1009,这个就是偏移地址,别忘记加上ImageBase(文件基地址),通过PEInfo得到基地址为0x6AE80000,所以要找的地址为0x6AE81009
(5) 我们看到1007这里是一条mov指令 ,不管它,看到1009开始读(记得是大端模式) 6AE84000,看到是不是和对应汇编指令的地址一样呢,这个就说明这个地方的地址需要重定位。基址重定位表记录的就是所有需要重定位的地址。