杂
参考:
基址重定位的作用及详细解析
小甲鱼PE详解之基址重定位详解
PE文件结构(五)基址重定位
《程序员的自我修养:链接、装载与库》
什么是基址重定位
重定位就是把程序的逻辑地址空间变换成内存中的实际物理地址空间的过程,也就是说在装入时对目标程序中指令和数据的修改过程。他是实现多道程序在内存中同时运行的基础。
为什么需要基址重定位
每个PE文件都有一个首选基地址,它表示模块被映射到进程地址空间时最佳的装载位置。
而代码中有许多语句都是使用直接寻址方式表示的这些地址是以PE文件被加载到首选基地址的条件下确定的,但如果PE文件不能被加载到首选基地址处,则代码中所有的直接寻址指令都会出现问题,这时就需要进行重定位对指令进行修正。
如何进行基址重定位
从PE头拿到建议装入地址
直接寻址指令的地址修正为:原双字地址 + 实际装入地址 - 建议装入地址
重定位表的数据结构
基址重定位表是由一个个IMAGE_BASE_RELOCATION结构体构成的
IBR结构体如下:
VirtualAddress:需要进行重定位的块的起始RVA
SizeOfBlock:针对此块的重定位表的大小,包括VirtualAddress字段和SizeOfBlock字段及后面的TypeOffset数组。
还有一个变量紧随其后,但是不属于此结构体
TypeOffset:WORD类型的数组,每一项2B,其中高4b是重定位类型,低12b是:需要重定位的指令地址相对于此块的起始RVA的偏移量。
重定位类型的值如下:
实例
PE文件名:libdll_generate.dll
LordPE打开,重定位表的RVA:96000H
转FileOffset为90000H
C32ASM跟进,查看第一个IBR结构体。
需要进行重定位的块的起始RVA:1000H
针对此块的IBR的大小:68H即104B
则TypeOffset数组的大小为:104B - 8B = 96B,数组项数为 96B / 2B = 48项
TypeOffset数组如下:
TypeOffset[0]:301DH,即重定位类型为3,需要重定位的RVA在101DH
TypeOffset[1]:3022H,即重定位类型为3,需要重定位的RVA在1022H
两个地址分别转FO为:61DH和622H
查看其首选基地址(镜像基址)为6C0C0000H
OllyICE加载,因为代码段偏移是1000H,则知其被加载到了首选基地址处
进而可以看到其地址不需进行修正:
如果没有加载到首选基地址处,就需要修正了。