解析重定位表

基本概念

每个程序都会有一个4GB的虚拟内存,不是真正的物理内存。就相当于玩原神这样的游戏,角色往前走,前面生成地图,后面删除地图,移动起来就相当于一个最多4GB大小的游戏世界。其中,高2G的是内核使用的空间。也就是说,3环程序处理底2G内存,内核程序处理高2G内存。

而一个程序里面可以有许多个PE文件。其中,dll程序的PE文件通常贴在高位,一般像71B10000这样以7开头的地址很有可能就是dll程序。
在这里插入图片描述

重定位表有什么用

当多个应用程序加载地址重复,例如:我们有一个dll程序贴在1000000这个地址处,此时,我们有另一个dll程序打算也贴在这里时,却发现已经有数据占住了,就只好往下贴。假设贴在了200000处,此时就会出现exe找不到dll程序的情况。

特别说明:
1.一般情况下,exe程序都是可以按照ImageBase的地址进行加载的,因为exe程序拥有自己独立的4GB虚拟内存空间,而dll不是。dll是有exe使用它到时候,它才会加载到相关的exe内存空间的。
2.为了提高搜索速度,模块间地址也是需要对齐的,模块对齐的值是10000H,也就是64k

在这里插入图片描述
上图是全局变量的反汇编。我们可以看出,编译器写的是绝对地址,也就是说,一旦程序的地址有变,我们就很难再找到这个程序在哪里。因此,重定位表就是为了我们重新定位这些地址改变的程序而出现的。
1.也就是说,只要程序能够按照预定的ImageBase来加载的话,就不需要重定位表。而由于不同的exe加载dll的顺序不同,所以dll通常不能按照预定的ImageBase作起始加载位置。因此,exe程序很少有重定位表,而绝大多数dll都有重定位表。
2.一旦某个模块没有按照ImageBase进行加载,那么所有的类似上图中的地址都需要修正。否则,引用的地址就是无效的。

重定位表

从数据目录表的第六个结构中找,找到它的第一个成员的值,就是重定位表的地址(RVA),然后将这个RVA转换成FOA就找到了重定位表在文件中的具体位置了
在这里插入图片描述
而得到的FOA地址指向的重定位表可能不止一个,具体结构见下图:
在这里插入图片描述
这整个重定位表的结构由许多块组成,其中每个块的前八个字节是VirtualAddress和SizeOfBlock。其中第二个成员SizeOfBlock则存的是这个块的大小。
另外,我们这里的每个块除了前8字节固定是VirtualAddress和SizeOfBlock外,后面的数据其实是一个存储了所有要改的地址的目录,每个数据2字节。

假设:当我们想要存10000个数据的时候,我们知道,32位程序的每个地址大小为4字节,也就是说,存10000个数据需要100004=40000字节大小的空间。此时,我们可以随便提一个值,假设是8000,见上图。然后我们再建一张小表,存储12、23、34、45这样的偏移值,当8000加上这个偏移值得到的结果就是我们要存储的32位程序的地址大小。此时,我们只需要在最前面用一个4字节大小储存这个提出的值,然后后面的4字节大小的地址全部换成2字节大小的偏移,就可以实现同样的功能。重定位表就是采用的这种思想,相比较数据个数4的内存,减少了一半的内存需求。而这个提出来的值存放在哪儿呢?我们将他存放在每个块的第一个成员VirtualAddress中。

在计算机的存储中有一个概念叫"页",页是一个数据块,一页的大小为1000h。重定位表中就用到了这个概念。每个块中的存储需要修改的位置的这个数据目录有多大?编译器把每一页中需要修改的数据放进了一个块里面。

抛出另一个问题:一个页的大小是1000h,换算成10进制就是4096,也就是2的12次方大小。也就是说,我们用12位数据就能访问这整个页中的所有数据。而由于内存对齐,我们每个数据的大小对齐成了两个字节,也就是16位。因此,每个数据的只有后12位存储的是偏移值。也就是低12位的值拿出来加上VirtualAddress中存的数据得到的就是我们需要修改的地址。而高4位用来干什么?这里的高四位用来判断低12位的地址是否是需要被修改的。如果高四位的值存的是3(也就是0011),就代表需要修改;如果是其他的值,我们就可以不用管这个数据。

在重定位表的最后,会存储一个值为0的VirtualAddress和值为0的SizeOfBlock。当判断出这两个值为0时,则代表我们所有的块遍历结束。

至于重定位表中每个块的项有多少?由 (块大小-8)/2 可以算出这个数量。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值