PE文件详解八:IMAGE_BASE_RELOCATION STRUC基址重定

本文详细介绍了PE文件中的基址重定位机制,包括IMAGE_BASE_RELOCATION结构、VirtualAddress的作用、SizeOfBlock的含义及TypeOffset数组的构成。此外还解释了不同重定位类型的含义及其如何应用于指令。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PE文件详解八:IMAGE_BASE_RELOCATION STRUC基址重定

什么是基址重定位?
答:重定位就是你本来这个程序理论上要占据这个地址,但是由于某种原因,这个地址现在不能让你霸占,你必须转移到别的地址,这就需要基址重定位

但凡涉及到直接寻址的指令都需要进行重定位处理!

复制代码
IMAGE_BASE_RELOCATION STRUC 【基址重定位位于数据目录表的第六项,共8+N字节】
{
+00 h DWORD VirtualAddress ;重定位数据开始的RVA 地址
+04 h DWORD SizeOfBlock ;重定位块得长度,标识重定向字段个数
+08 h WORD TypeOffset ;重定项位数组相对虚拟RVA,个数动态分配
};
IMAGE_BASE_RELOCATION ENDS
复制代码

1.VirtualAddress 是 Base Relocation Table 的位置它是一个 RVA 值;
2.SizeOfBlock 是 Base Relocation Table 的大小;
3.TypeOffset 是一个数组,数组每项大小为两个字节(16位),它由高 4位和低 12位组成,高 4位代表重定位类型,低 12位是重定位地址,它与 VirtualAddress 相加即是指向PE 映像中需要修改的那个代码的地址。

TypeOffset高位字节的代码定义:

复制代码
IMAGE_REL_BASED_ABSOLUTE (0) 使块按照32位对齐,位置为0。
IMAGE_REL_BASED_HIGH (1) 高16位必须应用于偏移量所指高字16位。
IMAGE_REL_BASED_LOW (2) 低16位必须应用于偏移量所指低字16位。
IMAGE_REL_BASED_HIGHLOW (3) 全部32位应用于所有32位。
IMAGE_REL_BASED_HIGHADJ (4) 需要32位,高16位位于偏移量,低16位位于下一个偏移量数组元素,组合为一个带符号数,加上32位的一个数,然后加上8000然后把高16位保存在偏移量的16位域内。
IMAGE_REL_BASED_MIPS_JMPADDR (5) Unknown
IMAGE_REL_BASED_SECTION (6) Unknown
IMAGE_REL_BASED_REL32 (7) Unknown
复制代码

### IMAGE_BASE_RELOCATION 结构体的义与使用 在 Windows PE 文件格式中,`IMAGE_BASE_RELOCATION` 是一个关键结构体,用于支持动态基地址位(Dynamic Base Relocation)。以下是关于该结构体的义和使用方法的详细说明。 #### 结构体义 `IMAGE_BASE_RELOCATION` 的义如下: ```c typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; // 当前块对应的区域RVA DWORD SizeOfBlock; // 当前块的总大小(包括VirtualAddress的大小) WORD TypeOffset[]; // 类型与偏移量组合列表 } IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; ``` - **VirtualAddress**: 表示当前位块的相对虚拟地址(RVA),即此块在内存中的起始位置[^3]。 - **SizeOfBlock**: 表示当前位块的总大小,包含 `VirtualAddress` 和 `TypeOffset` 列表的大小[^3]。 - **TypeOffset**: 这是一个可变长度的数组,每个元素由 16 位组成,其中高 4 位表示位类型,低 12 位表示偏移量[^3]。 #### 使用方法 `IMAGE_BASE_RELOCATION` 结构体通常通过以下方式使用: 1. **解析位表** 位表位于 PE 文件的 `.reloc` 节区中。通过 `IMAGE_OPTIONAL_HEADER.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress` 可以找到位表的起始 RVA[^3]。然后依次解析每个 `IMAGE_BASE_RELOCATION` 块。 2. **计算位项的数量** 每个位块的大小由 `SizeOfBlock` 字段决。可以通过以下公式计算出 `TypeOffset` 数组的元素数量: \[ n = \frac{\text{SizeOfBlock} - 8}{2} \] 其中,8 是 `VirtualAddress` 和 `SizeOfBlock` 占用的字节数,2 是每个 `TypeOffset` 的字节数[^4]。 3. **应用位** 对于每个 `TypeOffset`,需要根据其高 4 位的类型值执行不同的操作。例如,常见的类型值为 `IMAGE_REL_BASED_HIGHLOW`,表示将目标地址调整为新的基地址。 #### 示例代码 以下是一个简单的代码示例,展示如何解析 `IMAGE_BASE_RELOCATION` 结构体: ```c #include <windows.h> #include <stdio.h> void ParseRelocationTable(PBYTE pImageBase) { PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(pImageBase + ((PIMAGE_DOS_HEADER)pImageBase)->e_lfanew); PIMAGE_DATA_DIRECTORY pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; if (pDataDir->Size == 0) return; PBYTE pRelocData = pImageBase + pDataDir->VirtualAddress; PIMAGE_BASE_RELOCATION pReloc = (PIMAGE_BASE_RELOCATION)pRelocData; while ((DWORD_PTR)pReloc < (DWORD_PTR)pRelocData + pDataDir->Size) { printf("VirtualAddress: 0x%X, SizeOfBlock: 0x%X\n", pReloc->VirtualAddress, pReloc->SizeOfBlock); WORD* pTypeOffset = (WORD*)((PBYTE)pReloc + sizeof(IMAGE_BASE_RELOCATION)); int nEntries = (pReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); for (int i = 0; i < nEntries; ++i) { printf(" TypeOffset[%d]: 0x%X\n", i, pTypeOffset[i]); } pReloc = (PIMAGE_BASE_RELOCATION)((PBYTE)pReloc + pReloc->SizeOfBlock); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值