今天我们说一下PE结构中重定位表。
在说之前我们先来想一个问题
假设你的程序有一个全局变量(记住不限于变量),全局变量就不用我解释了把,这是被写死的数据是根据Image Base 再加上 全局变量所在的地址。 什么意思呢看下图就知道了
成员 Image Base 是 00400000
就是字符串所在的地址 00403000
仔细看压入的字符串地址,这是一个被写死的地址,那么这个时候如果 程序没有被载入指定的地址空间会发生什么呢?
肯定访问不到正确的数据然后程序就会崩溃但是实际上来说重定位表主要还是在sys/dll 类的PE文件中大量使用。
换个思路说,打个比方 两个dll或者sys 的载入地址都是 00400000 那么 如果第一个载入到了00400000 那么第二会加载到哪里呢?肯定不能和已经加载了的抢位置啊是吧,所以就会换个没有占用的加载,然后重新定位 向上图所示的那种写死了的数据这样就可以解决问题了。
下面开始查找
数据目录数组 的第5个成员就是 重定位表的信息
然后我们查看节区的信息,发现节区的起始RVA和重定位表的RVA是一样的那么就可以直接根据 Pointer to Raw Data成员的值来直接访问重定位表
这里我们要说一下重定位表的结构。
重定位表也是一个结构体数组,每一个数组元素描述了一页(4KB)内的重定位信息。
typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress;//这是RVA DWORD SizeOfBlock;// 结构体大小,包含TypeOffset // WORD TypeOffset[1]; } IMAGE_BASE_RELOCATION;
这里说一下重定位表 不止一个 那么我们如何知道有多少个重定位表呢
很简单 通过 VirtualAddress + SizeOfBlock 就可以访问到下一个重定位表,然后判断是否为NULL或者0x00000000
然后说一下如果计算 重定位表中的TypeOffset成员的数量 ( SizeOfBlock - 8(VirtualAddress 和 SizeOfBlock的大小))/ 2(这是Typeoffset成员的大小) 就等于多少个成员。
然后仔细说一下TypeOffset成员
这个成员的高4位是状态码 然后低12位是具体的RVA
状态码的具体含义如下
下面我们查看重定位表内具体的值
下面就开始根据上面的信息开始实战
VirtualAddress +
Typeoffset(低十二位) = RVA
1000 + 000 = 1000
下面我们查看1000地址下的数据信息,首先由于得到是RVA我们还是需要转换到FOA
我这里的1000转换到FOA是 400
我们仔细观察可以发现,400 往后四个字节保存的是一个地址 69E623F0
我们这个时候可以猜一下为什么RVA 1000 地址的内容会是这个值呢?
也不留悬念我们直接进OD看一下就知道了
刚一加载到内存中,我们就可以发现实际的加载位置和我们 Image Base的值不一样
那么这种情况就会发生重定位,实际加载位置和设置的加载位置完全一样的话。
由于加载的地址发生了变化所以我们只能根据新的 Image Base 来加上 RVA1000了
我们发现定位到的地址 是一个地址。但是这又和我们 重定位表有什么关系呢?
先别急我们看一下之前我们找到的数据,我们发现400文件偏移保存的是一个地址 69E623F0
那么和774323F0 对比一下 69E623F0,我们发现除了后面四位完全对不上啊。先别急这里有一个公式
新的 Image Base 减去 旧的 Image Base 然后再加上 69E623F0
773D0000 - 69E00000 + 69E623F0 = 774323F0
那么根据我们计算来的值 在和找到的地址对比一下
774323F0
774323F0
发现完全一样,那么由此可见,可以推出一种想法。
即重定位表中的 VirtualAddress + Typeoffset(低十二位)得到的是一个 偏移,那么这个偏移是用来指向需要重定位的数据的。
(记住不限于函数,意思就是说有可能是字符串,有可能是全局变量什么的。)
由此我们便可以推算出流程 。
首先获得实际加载的地址判断是否和 预设的加载地址相同,如果相同就跳过
如果不相同那么 便取出 VirtualAddress + Typeoffset(低十二位)再加上新的加载地址
得到需要修改的地址,然后再通过 (新的Image Base 减去 旧的Image Base 然后再加上 旧的的相关数据地址)这个公式修改数据。
然后整个程序完整重定位的工作。
第三篇关于PE的文章,也是结束篇因为整个PE文件中比较难的就是导出表和导入表还有重定位表了。
同样新手的帖子,如果有错误还请各位大佬指正