PE重定位表
Posted 不会写代码的丝丽
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PE重定位表相关的知识,希望对你有一定的参考价值。
前言
首先看一个问题,假设我们的某个EXE/DLL
首选加载地址是0x10000
,但实际由于随机基质等原因实际加载地址
与首选地址
产生的偏移
。
我们首先看一个exe的静态反编译结果
我们看到00411E98
这个地址的反汇编指令是MOV EAX,[41A014H]
我们再看看动态加载这个EXE后的结果
这个你可以明显看到这个指令变成了eax dword ptr[09FA014h]
,这个读取地址从41A014H
到09FA014h
变化。这就是因为基地址实际装载有变化因此需要对于实际地址的命令做出改变。
为了解决这类绝对地址随着实际加载地址的改变PE提出了重定位表的概念
重定位表
重定位表数据偏移放在数据目录第六项
我们看一个例子
这个例子中第六项显示出导出数据VA为 1F000h
大小为888(十进制 十六进制为378)
字节。
另外我们注意这个示例中存在一个section 名字是.reloc
,VA为 1F000h
大小为600(十六进制,十进制1536)
,也就是重定位数据会放在这个节中
这个重定位节的数据结构比较麻烦,.reloc
存在若干个IMAGE_BASE_RELOCATION
+n* TypeOffset
组成
typedef struct _IMAGE_BASE_RELOCATION
DWORD VirtualAddress;
DWORD SizeOfBlock;
// WORD TypeOffset[1];
IMAGE_BASE_RELOCATION;
我们现在来详细解释下相关具体字段
Offset | Size | Field | Description |
---|---|---|---|
0 | 4 | Page RVA | 这个地址加上镜像首选基质 最后分别和每个TypeOffset加和得到需要重定位的地址 |
4 | 4 | Block Size | 整个IMAGE_BASE_RELOCATION大小包含若干TypeOffset以及Block Size,Page RVA的大小 |
8 | 2 | TypeOffset | 低12表示偏移值,高4位表示偏移类型 |
n | 2 | TypeOffset | 同上 |
通过上面简述我们可以到一个结论IMAGE_BASE_RELOCATION中存在TypeOffset的数量是:
n= ([Block Size] - sizeof(Block Size)+sizeof (Page RVA))/sizeof (TypeOffset)
我们进行常量替换得到
n =([Block Size] -8)/2
TypeOffset
高4位类别如下所示:
我们本例中重定位范围为:
[1F000h-1F378h]
对应文件地址[9000h-9378h]
我们举例分析其中的第一个
00 10 01 00 4C 00 00 00
Offset | Size | Field | Value |
---|---|---|---|
0 | 4 | Page RVA | 00011000 |
4 | 4 | Block Size | 0000004C |
我们带入公式
n =(4c -8)/2= 22
可见第一个存在22个TypeOffset
因此我们高亮整个数据结构IMAGE_BASE_RELOCATION
区域如下图
Offset | Size | Field | Value |
---|---|---|---|
0 | 4 | Page RVA | 00011000 |
4 | 4 | Block Size | 0000004C |
8 | 2 | TypeOffset | 高四位:3 低12位:71F |
10 | 2 | TypeOffset | 高四位:3 低12位:73E |
略 | 2 | TypeOffset | 略 |
我们举例其中两个偏移地址的计算:
本例中:
Page RVA =00011000
Base:400000h(这里从本例PE文件给出)
因此第一个重定位的偏移地址为:
00011000+400000+71F=41171F
第二个重定位的偏移地址为:
00011000+400000+73E=41173E
代码实战
我们利用上面所学的知识实现一个功能,手动加载dll
并处理重定位,然后调用相关函数。
以上是关于PE重定位表的主要内容,如果未能解决你的问题,请参考以下文章