PE重定位表

PE文件基址重定位(Base Relocation),程序编译时每个模块有一个优先加载地址ImageBase,这个值是连接器给出的,因此连接器生成的指令中的地址是在假设模块被加载到ImageBase前提之下生成的,那么一旦程序没有将模块加载到ImageBase时,那么程序中 的指令地址就需要重新定位,例如:假设一个可执行文件,基址是0x400000,在这个image偏移0x1234处是一个指针,指向一个字符串,字符串始于实际地址0x404002处,所以指针应该是0x404002,加载文件时,由于种种原因,加载器决定把他加载到0x600000处,连接器假设的地址和实际的地址之差成为delta,上例delta为0x200000,整个位置提高了0x200000,那么字符串位置应该为0x604002,原来指向字符串的指针就错误了,所以要把delta加到指针值中,为了让加载器有这样的能力做调整,可执行文件内含许多个【基址重定位项】,给那些存放指针的位置使用,加载器必须把delta加载到各个基址上。本例中应该把0x200000加给原来的指针值,0x404002,并将0x604002写回原处。

下面我们来介绍一下【基址重定位项】,加载器就是利用它来知道模块是否按预期的位置加载,哪些指令是需要修改的。因此我们研究的重点将是【基址重定位项】,首先加载器也是通过数据目录来定位【基址重定位项】,【基址重定位项】被包装为一系列连续区段,每一个区段来描述一个4K PAGE(也就是一页)的重定位信息,长短不一(每页中需要重定位的指令数目也不一样),它们以一个IMAGE_BASE_RELOCATION结构作为开始,格式如下:

DWORD VirtualAddress重定位内存页的起始RVA,每一个【基址重定位项】的偏移位置(即下面的TypeOffset的低12位,它是指令相对于它所在页的第一条指令的偏移),必须加上重定位页的RVA才是一个真正的RVA,指向【基址重定位项】

DWORD SizeOfBlock:结构大小,在加上跟着后面的所有【基址重定位项】(都是WORDS),为了决定【基址重定位项】的个数,=(SizeOfBlock-Sizeof(IMAGE_BASE_RELOCATION)(8个字节))/2(WORD占2个字节);例如此值为44,则个数为44-8/2=18.

总结:IMAGE_BASE_RELOCATION包含两个成员,一个是VirtualAddress,包含自身内存页起始位置RVA,另一个SizeOfBlock,表明这个结构有多大。

WORD TypeOfOffset

这并不是单独一个WORD,而是一个WORDS组,数组元素个数可以有上一个式子计算得到,每一个WORD的最底部12位代表【基址重定位项】的位置偏移,但必须在加上IMAGE_BASE_RELOCATION表头中VirtualAddress,最高4位是【基址重定位项】的型态。对于在Intel CPU中的PE文件,你将看到两种状态,0(IMAGE_REL_BASED_ABSOLUTE)此一【基址重定位数据项】无意义,只是用来充数而已,使所有【基址重定位项】总数为DWORD倍数。3(IMAGE_REL_BASED_HIGNLOW):把delta值加到欲计算的RVA值,另外还有其他状态在WINNT.h中,它们大部分是给i386以外的的CPU使用。

下面给出一些【基址重定位项】,请注意其中的RVA已经被IMAGE_BASE_RELOCATION中的VirtualAddress校正过。

VirtualAddress:00001000  Size0000012C

000001032 HIGHLOW

00000106D HIGHLOW

0000010AF  HIGNLOW

......

VirtualAddress:00002000 Size0000009C

000020A6  HIGHLOW

00002110  HIGHLOW

00002136  HIGHLOW

00002156  HIGHLOW

........

VirtualAddress:000003000 Size00000114

0000300A  HIGHLOW

0000301E  HIGHLOW

0000303B  HIGHLOW

0000306A  HIGHLOW

通过上面的例子我们可以看到相邻区段正好相差0X1000,也就是4K,证实了上面所说的“每一个区段描述image一个4K Page(也就是一页)的重定位信息”同时我们可以看到第一个区段的VirtualAddress是00001000,正好是.text起始RVA。

 现在问题基本明白了,一旦模块没有价加载到预期地址,编译器就会根据【基址重定位项】去修正哪些需要修正的指令,这样程序就可以正常执行了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值