windows PE Image 文件分析(6)--- .reloc 节与 base relocation table

本文深入探讨了Image Base Relocation及Base Relocation Table在映像文件中的作用,解释了如何通过计算ImageBase偏移量与新ImageBase来实现地址重定位,以确保32位应用程序在64位系统上正确运行。

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



.reloc 节和 base relocation table 仅存在于 Image 文件中,用于当映像被加载运行的 ImageBase 改变后,对映像内的使用的地址进行重定位。

需要进行 ImageBase 重定位的映像性能会变得很糟糕。32 位的应用程序在 64 位系统上运行就是一个典型的例子。

下面以前面的 32 位 helloworld.exe 映像为例子

 

1. ImageBase 重定位

编译器会为每个映像建立一个首选的 ImageBase 值,ImageBase 是映像被加载运行时所有地址的基地址,因此 ImageBase 显得非常重要。


1.1 映像的 ImageBase 值

典型地 helloworld.exe 映像的 ImageBase 被设为:0x00400000

OPTIONAL HEADER VALUES
             10B magic # (PE32)
           10.00 linker version
            3C00 size of code
           12000 size of initialized data
               0 size of uninitialized data
           1120D entry point (0041120D) @ILT+520(_wWinMainCRTStartup)
            1000 base of code
            1000 base of data
         400000 image base (00400000 to 00428FFF)
            1000 section alignment
             200 file alignment
            5.01 operating system version
            0.00 image version
            5.01 subsystem version
               0 Win32 version
           29000 size of image
             400 size of headers
               0 checksum
               2 subsystem (Windows GUI)

32 位映像的 ImageBase 都被设为 0x00400000,而 64 位映像的 ImageBase 被设为 0x00000001_40000000


1.2 映像内的地址使用

下面是从 helloworld.exe 映像中的 .text 节摘下来的数据:

  00411490: 6A 64 68 00 72 41 00 6A 67 8B 45 08 50 FF 15 C0  jdh.rA.jg.E.P?.à
  004114A0: 83 41 00 3B F4 E8 D2 FC FF FF 8B F4 6A 64 68 38  .A.;?èòü??.?jdh8

注意上面的蓝色粗体部分,实际上这是一条 call 指令的机器代码,这条指令是:

0041149D:  FF 15 C0 83 41 00      call dword ptr [004183C0h]

实际上,这就是调用 LoadString() 函数的一条指令,LoadString() 的地址就放在 0x004183C0 地址上。

当映像被加载后的 ImageBase 还是 0x00400000,那么这个映像就不需要 ImageBase 重定位,但是很遗憾,特别是当 32 位程序在 64 位系统上运行时,这个情况就发生。


1.3 ImageBase 重定位

在我的实例中,这一次 helloworld.exe 的运行,ImageBase 被加载到 0x012b0000,没错就需要进行 ImageBase 重定位处理。

call dword ptr [004183C0h]

这个情况下,这个 0x004183C0 地址就会产生错误,加载器需要将它重新重位在:0x012C83C0 地址上。

这个 0x012C83C0 是等于:0x004183C0 - 0x00400000 + 0x012b0000 = 0x012C83C0

计算方法就是得到基于 ImageBase 的偏移量再加上新的 ImageBase 值,这个 0x012C83C0 就是正确的函数地址:

012C14B9 FF 15 C0 83 2C 01    call        dword ptr [__imp__LoadStringW@16 (12C83C0h)] 

上面就是 visual studio 2010 调试下得出的 call 指令

 

2. .reloc 节

现在转入正题,看看 helloworld.exe 映像的 .reloc 节,如下表:

.reloc 节
VirtualSize
0x00000564
VirtualAddress
0x00028000
SizeOfRawData
0x00000600
PointerToRawData
0x00015400
PointerToRelocations
0
PointerToLinenumbers
0
NumberOfRelocations
0
NumberOfLinenumbers
0
Characteristics
0x42000040

helloworld.exe 的 .reloc 位置在 0x00428000(ImageBase + VritualAddress),它在映像文件的位置是 0x00015400 占用 0x600 bytes 的文件空间

 

3. base relocation table

base relocation bale
VirtualAddress
0x00028000
size
0x340

base relocation table 存放在 .reloc 节里,大小为 0x340 bytes

base relocation table 由 IMAGE_BASE_RELOCATION 结构和它的 Entry 组成


3.1 IMAGE_BASE_RELOCATION 结构

这个结构在 WinNT.h 的定义为:

//
// Based relocation format.
//

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
//  WORD    TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

VirtualAddress 是 base relocation table 的位置,它是一个 RVA 值,SizeOfBlock 是 Base Relocation Table 的大小


3.2 Entry 结构

Entry 结构只有一个 WORD 值,它紧跟着 IMAGE_BASE_RELOCATION 结构后面,但是这个 WORD 却分为两个部分:

位域
长度
描述
Type
[15:12]
4 Bits
高 4 位用来表示 Base Relocation Table 的类型
Offset
[11:0]
12 Bits
低 12 位是 RVA 值,指出需要重定位的位置

这个 12 位的 Offset 值是基于 IMAGE_BASE_RELOCATION 结构的 VirtualAddress, 而 VirtualAddress 是基于 ImageBase 的 RVA 值

因此最终的 Offset 值应该是 ImageBase + VirtualAddress + Offset

在 WinNT.h 中定义了 Base Relocation Table 的类型:

//
// Based relocation types.
//

#define IMAGE_REL_BASED_ABSOLUTE              0
#define IMAGE_REL_BASED_HIGH                  1
#define IMAGE_REL_BASED_LOW                   2
#define IMAGE_REL_BASED_HIGHLOW               3
#define IMAGE_REL_BASED_HIGHADJ               4
#define IMAGE_REL_BASED_MIPS_JMPADDR          5
#define IMAGE_REL_BASED_MIPS_JMPADDR16        9
#define IMAGE_REL_BASED_IA64_IMM64            9
#define IMAGE_REL_BASED_DIR64                 10

大部分的 Base Relocation Table 类型都是 IMAGE_REL_BASED_HIGHLOW 类型,表示被重定位的是 32 位的值。

举个例子,有如下的 Entry 值:

  • 93 34

这个 Entry 是 0x3493,那么 Base Relocation Table 类型是 也就是 IMAGE_REL_BASED_HIGHLOW 类型,它的 Offset 值是 0x0493,那么需要重定位的位置在 0x00411493

这个值计算方法是:ImageBase + VirtualAddress + Offset = 0x00400000 + 0x11000 + 0x493 = 0x00411493

 

4. helloworld.exe 映像的 Base Relocation Table

00428000  00 10 01 00          // VirtualAddress = 0x00011000
00428004  DC 00 00 00          // SizeOfBlock = 0x000000DC


// Entries

00428008  93 34               // type = 3, offset = 493
0042800A  9F 34               // type = 3, offset = 49F 
0042800C  AF 34               // type = 3, offset = 4AF
0042800E  BB 34               // type = 3, offset = 4BB
00428010  F4 34               // type = 3, offset = 4F4 
00428012  10 35               // type = 3, offset = 510 
00428014  2F 35               // type = 3, offset = 52F 
00428016  46 35               // type = 3, offset = 546 
00428018  59 35               // type = 3, offset = 559 
0042801A  6F 35               // type = 3, offset = 56F 
0042801C  94 35               // type = 3, offset = 594
0042801E  A0 35               // type = 3, offset = 5A0


... ...

 

004280DC  00 20 01 00          // VirtualAddress = 0x00012000
004280E0  20 01 00 00          // SizeOfBlock = 0x00000120

004280E4  0C 30               // type = 3, offset = 00C 
004280E6  15 30               // type = 3, offset = 015 
004280E8  1E 30               // type = 3, offset = 01E 
004280EA  23 30               // type = 3, offset = 023 
004280EC  4D 30               // type = 3, offset = 04D 
004280EE  57 30               // type = 3, offset = 057

... ...

第 1 个 base relocation table 的 size 是 0xDC bytes,因此,下一个 base relocation table 就在 0x004280DC 处

下面是使用 dumpbin 得出的 base relocation table 结果:

BASE RELOCATIONS #7
   11000 RVA,       DC SizeOfBlock
     493  HIGHLOW            00417200  ?szTitle@@3PA_WA (wchar_t * szTitle)
     49F  HIGHLOW            004183C0  __imp__LoadStringW@16
     4AF  HIGHLOW            00417138  ?szWindowClass@@3PA_WA (wchar_t * szWindowClass)
     4BB  HIGHLOW            004183C0  __imp__LoadStringW@16
     4F4  HIGHLOW            004183C4  __imp__LoadAcceleratorsW@8
     510  HIGHLOW            004183C8  __imp__GetMessageW@16
     52F  HIGHLOW            004183CC  __imp__TranslateAcceleratorW@12
     546  HIGHLOW            004183D0  __imp__TranslateMessage@4
     559  HIGHLOW            004183D4  __imp__DispatchMessageW@4
     56F  HIGHLOW            00411590
     594  HIGHLOW            00411598
     5A0  HIGHLOW            004115A4


... ...

   12000 RVA,      120 SizeOfBlock
       C  HIGHLOW            00417734  ___native_startup_state
      15  HIGHLOW            00417734  ___native_startup_state
      1E  HIGHLOW            00415618  ___xi_z
      23  HIGHLOW            0041530C  ___xi_a
      4D  HIGHLOW            0041733C
      57  HIGHLOW            00417734  ___native_startup_state

与 dumpbin 的结果是相符的。


版权 mik 所有,转载请注明出处

<think>好的,我现在需要帮助用户了解如何从PE可执行文件中移除.reloc区。根据用户提供的引用内容,我需要整理出一个清晰的步骤指南。首先,我应该确认用户可能的需求:他们可能是在优化可执行文件的大小,或者出于其他目的需要删除.reloc区。需要注意的是,删除.reloc可能会影响程序的兼容性,尤其是在地址空间随机化(ASLR)的情况下,但根据引用[2]和[3],对于EXE文件来说,删除后通常仍能正常运行,而DLL或系统文件可能不行。 接下来,我需要从提供的引用中提取关键步骤。引用[2]提到使用PEView和Win Hex Editor手动删除,并指出.reloc通常位于最后。另外,引用[1]展示了删除后文件大小减少的例子。我需要将这些信息整合成一个步骤流程,确保用户能按部就班操作。 步骤可能包括:使用工具定位.reloc区、调整区头、修改文件大小、更新PE头中的相关字段。需要注意,手动编辑二进制文件存在风险,可能需要备份。同时,要提醒用户删除.reloc可能影响ASLR,尽管EXE文件可能不受影响,但需根据具体情况评估。 还需要考虑用户可能遇到的问题,例如如何找到DataDirectory[5]的地址,或者如何确保没有其他依赖.reloc的情况。此外,是否需要使用自动化工具还是手动操作,引用中提到的工具是否仍然适用,可能需要进一步说明。 最后,生成相关问题,确保覆盖用户可能的后续疑问,比如其他优化方法、ASLR的影响,或者自动化工具推荐。</think>### 如何从PE可执行文件中删除.reloc区? #### 操作步骤 1. **备份原始文件** 在修改前务必备份可执行文件,避免操作失误导致文件损坏。 2. **定位.reloc区** - 使用工具(如PEView或CFF Explorer)查看PE文件结构。 - 在`IMAGE_OPTIONAL_HEADER`的`DataDirectory[5]`中获取基址重定位表的RVA和大小[^2][^3]。 - 确认.reloc区位置(通常位于所有区末尾)。 3. **删除.reloc区** - **修改区头**:将.reloc区对应的`IMAGE_SECTION_HEADER`内容清零,或删除其条目。 - **调整文件大小**:用十六进制编辑器(如Win Hex)直接删除.reloc区的二进制数据,并裁剪文件末尾对应的字数[^1][^2]。 - **更新PE头**: - 将`DataDirectory[5]`的`VirtualAddress`和`Size`设为0。 - 修改`NumberOfSections`字段,减少区总数。 4. **验证文件功能** 运行修改后的文件,测试其是否正常执行(注意:DLL/SYS文件删除.reloc可能导致崩溃,EXE文件一般不受影响)[^3]。 #### 注意事项 - **兼容性影响**:删除.reloc后,程序将无法支持ASLR(地址空间布局随机化),可能降低安全性[^2]。 - **工具推荐**:可使用自动化工具(如`LordPE`或`PE Tools`)简化操作,减少手动编辑错误风险。 - **文件对齐**:删除后需检查区对齐是否符合PE格式要求(如文件对齐值一般为0x200)。 ```plaintext 示例修改前后对比(引用[1]): 原始文件大小:7168字 删除.reloc后:减少400H(1024字)→ 最终大小6144字 ``` ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值