PE结构详解(四)

基址重定位详解

转自:http://blog.fishc.com/1629.html 

什么是基址重定位?

重定位就是你本来这个程序理论上要占据这个地址,但是由于某种原因,这个地址现在不能让你霸占,你必须转移到别的地址,这就需要基址重定位。

对于每个EXE文件来说用不到基地址重定位,而对于DLL文件来说就需要了,因为操作系统并没有为其分配4GB的虚拟空间。

我们需要对程序中的哪些语句(指令)进行基址重定位呢?

答案是 —— 但凡涉及到直接寻址的指令都需要进行重定位处理!(那什么是直接寻址? 咱在零基础入门学习汇编里边讲得很清楚啦,只要在机器码中看到有地址的,那就叫直接寻址……那有没有间接的? 肯定哈,间接的就是地址被间接的保存起来,例如存放在寄存器eax, 然后通过访问寄存器来获取地址,那就叫间接~)

系统对一条指令进行重定位需要哪些信息?

现在就假设重定位后的基地址由原来的10000000h 变为 20000000h了,那么类似这样的语句:inc dword ptr [10003000] 应该改成 inc dword ptr [20003000] 。

注意,重定位的算法我们可以总结为:将直接寻址指令中的双字地址加上模块的实际装入地址与模块建议装入地址之差。

PE格式详细讲解10 – 系统篇10|解密系列

那有些朋友可能会问了,类似于“:10001038 E8CFFFFFFF call 1000100C”的指令,为什么后边显示的是call + 地址。

而机器码却不包含地址信息呢? CPU神了? 莫非地址信息被加密了?

其实不是的,学过汇编的朋友不知道还记不记得,小甲鱼在讲call 原理的时候用了大部分时间在谈几种跳转,其中经常遇到的就是“地址+偏移”的形式。

那这就能有个说得通的解释了:CFFFFFFFh 事实上就是一个偏移地址,记得咱这是little-edition,转换过来就是FFFF FFCFh,也就是等于-31h。

那么1000103Dh – 31h == 1000100Ch,Perfect! ^_^

问题四:系统对一条指令进行重定位需要哪些信息?

答:

我们还是拿上边那张图片来说事儿,我们说了上边的那些指令需要重定位。

现在就假设重定位后的基地址由原来的10000000h 变为 20000000h了,那么类似这样的语句:inc dword ptr [10003000] 应该改成 inc dword ptr [20003000] 。

注意,重定位的算法我们可以总结为:将直接寻址指令中的双字地址加上模块的实际装入地址与模块建议装入地址之差。

从上边的信息中我们看到,需要进行重定位需要三个因素:

1. 需要修正的地址(10003000h)

2. 建议装入的地址(10003000h)

3. 实际装入的地址(20003000h)

问题五:这些信息哪些应该被保存在重定位表中?

聪明的我们可以发现:

1. 建议装入的地址在PE 文件头中已经定义了

2. 实际装入的地址在没有被装载器装入我们根本无从得知,也就是说这事天不知地不知我们不知只有装载器知道……

因此,我们可以得到的结论是:PE 文件的重定位表(Base Relocation Table)中保存的就是文件中所有需要进行重定位修正的代码的地址。

IMAGE_BASE_RELOCATION STRUC
 
    VirtualAddress      DWORD        ?  ; 重定位数据开始的RVA 地址
    SizeOfBlock         DWORD        ?  ; 重定位块得长度
    TypeOffset          WORD         ?  ; 重定项位数组
 
IMAGE_BASE_RELOCATION  ENDS

VirtualAddress 是 Base Relocation Table 的位置它是一个 RVA 值;

SizeOfBlock 是 Base Relocation Table 的大小;

TypeOffset 是一个数组,数组每项大小为两个字节(16位),它由高 4位和低 12位组成,高 4位代表重定位类型,低 12位是重定位地址。

它与 VirtualAddress 相加即是指向PE 映像中需要修改的那个代码的地址。

IMAGE_REL_BASED_ABSOLUTE (0) 使块按照32位对齐,位置为0。

IMAGE_REL_BASED_HIGH (1) 高16位必须应用于偏移量所指高字16位。

IMAGE_REL_BASED_LOW (2) 低16位必须应用于偏移量所指低字16位。

IMAGE_REL_BASED_HIGHLOW (3) 全部32位应用于所有32位。

IMAGE_REL_BASED_HIGHADJ (4) 需要32位,高16位位于偏移量,低16位位于下一个偏移量数组元素,组合为一个带符号数,加上32位的一个数,然后加上8000然后把高16位保存在偏移量的16位域内。

IMAGE_REL_BASED_MIPS_JMPADDR (5) Unknown

IMAGE_REL_BASED_SECTION (6) Unknown

IMAGE_REL_BASED_REL32 (7) Unknown

原文地址:https://www.cnblogs.com/You0/p/4239024.html