基址重定位表

基址重定位表(Base Relocation Table),记录PE重定位时需要修改的硬编码地址的位置。

一般地,向进程的虚拟内存加载PE文件(EXE、DLL、SYS)时,文件会被加载到PE头的ImageBase所指的地址处。若加载的文件为DLL或SYS,且ImageBase位置加载了其他DLL或SYS文件时,则会进行PE重定位。

PE重定位是指PE文件无法加载到ImageBase所指位置时,而加载到其他地址所发生的一系列的处理行为。

因为在进程创建好之后,EXE文件会首先加载到内存中,因而EXE无须考虑重定位的问题。Windows Vista之后的版本引入ASLR机制,每次运行PE文件都会被加载到随机地址。

系统的DLL实际不会发生重定位,因为同一系统的kernel32.dll、user32.dll等会被加载到自身固有的ImageBase。

下面以Win7的notepad.exe程序为例,先使用PEView打开该程序查看ImageBase的值为01000000,再使用Ollydbg打开该程序查看。



可以看到,在EP代码中,方框中的地址是以硬编码的形式存在的。其中地址5810FC和581100是.text节区的IAT区域,地址58C0A4为.data节区的全局变量。每当在Ollydbg中重启notepad.exe程序,地址值就会随加载地址的不同而改变。这种使硬编码在程序中的内存地址随当前加载地址的变化而变化的处理过程,即为PE重定位。

在生成notepad.exe文件时,由于无法预测程序被实际加载到哪个地址,所以记录硬编码地址时以ImageBase为基准,但在程序运行瞬间经过PE重定位后,这些地址全部以加载地址为基准变换,最后程序得以正常执行而不发生错误。


PE重定位的基本原理:

1、在应用程序中查找硬编码的地址位置;

2、读取值后,减去ImageBase(VA转换为RVA);

3、加上实际加载地址(RVA转换为VA)。


基址重定位表:

基址重定位表位于PE头的DataDirectory数组的第六个元素(索引为5),如图:


其地址为0002F000,查看一下:


如图罗列了硬编码地址的偏移。

基址重定位表是IMAGE_BASE_RELOCATION结构体数组,其中第一个成员为VirtualAddress如地址2F000的值,第二个成员为SizeOfBlock如地址2F004的值,第三个成员为TypeOffset数组如2F008地址以下的值,以注释的形式存在,表示该结构体之下会出现WORD类型的数组,并且该数组元素的值就是硬编码在程序中的地址偏移。


基址重定位表的分析方法:

如上图,VirtualAddress的值为1000,SizeOfBlock的值为150,即TypeOffset数组的基准地址为RVA 1000,块的总大小为150。其中,TypeOffset值为2字节(16位)大小,由4位的Type和12位的Offset组成,比如TypeOffset数组的第一个元素值为3420,其中高4位的值“3”(IMAGE_REL_BASED_HIGHLOW)为Type,一般为PE文件,而64位的PE文件常见值为“A”,低12位是真正的位移、其值为420,下面公式计算程序中硬编码地址的偏移:

VirtualAddress + Offset = 1000 + 420 = 1420(RVA)

查看1420偏移处(程序被加载到00330000地址处、故RVA 1420即VA 00331420)是否存在要执行PE重定位操作的硬编码地址:



下面来简单演示PE重定位的过程。

运行notepad.exe程序,假设其被加载到00330000。

1、查找程序中硬编码地址的位置:

使用PEView查看RVAV 1420处的内容:


可以看到,RVAV 1420处保存着程序硬编码地址值010010C4。

2、读取值后,减去ImageBase值(VA转换为RVA):

010010C4 - 01000000 = 10C4

3、加上实际加载地址(RVA转换为VA):

10C4 + 00330000 = 003310C4

可以看到,和上图硬编码地址一致。

对于程序内硬编码的地址,PE装载器都会做如上处理,然后将值覆盖到同一位置。若TypeOffset值为0,则表明一个IMAGE_BASE_RELOCATION结构体结束。

猜你喜欢

转载自blog.csdn.net/ski_12/article/details/80636568