您的位置:首页 > 其它

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

2013-12-11 21:54 555 查看
.reloc 节和 base relocation table 仅存在于 Image 文件中,用于当映像被加载运行的 ImageBase 改变后,对映像内的使用的地址进行重定位。
需要进行 ImageBase 重定位的映像性能会变得很糟糕。32 位的应用程序64 位系统上运行就是一个典型的例子。
下面以前面的 32helloworld.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 节
VirtualSize0x00000564
VirtualAddress0x00028000
SizeOfRawData0x00000600
PointerToRawData0x00015400
PointerToRelocations0
PointerToLinenumbers0
NumberOfRelocations0
NumberOfLinenumbers0
Characteristics0x42000040
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 类型是 3 也就是 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 所有,转载请注明出处

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: