windows PE Image 文件分析 — .reloc 节与 base relocation table

.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 的结果是相符的。

发表评论