windows PE Image 文件分析(6)--- .reloc 节与 base relocation table 古城微笑少年丶 2022-09-19 01:55 112阅读 0赞 -------------------- **.reloc** 节和 **base relocation table** 仅存在于 **Image** 文件中,用于当映像被加载运行的 **ImageBase** 改变后,对映像内的使用的地址进行重定位。 需要进行 **ImageBase** 重定位的映像性能会变得很糟糕。**32 位的应用程序**在 **64 位系统**上运行就是一个典型的例子。 下面以前面的 **32** 位 ***helloworld.exe*** 映像为例子 ## 1. ImageBase 重定位 ## 编译器会为每个映像建立一个首选的 **ImageBase** 值,**ImageBase** 是映像被加载运行时所有地址的基地址,因此 **ImageBase** 显得非常重要。 ### 1.1 映像的 ImageBase 值 ### 典型地 ***helloworld.exe*** 映像的 **ImageBase** 被设为:**0x00400000** <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start; border:1px dotted rgb(204,204,204); table-layout:fixed"> <tbody> <tr> <td style="word-wrap:break-word"> <p>OPTIONAL HEADER VALUES<br> 10B magic # (PE32)<br> 10.00 linker version<br> 3C00 size of code<br> 12000 size of initialized data<br> 0 size of uninitialized data<br> 1120D entry point (0041120D) @ILT+520(_wWinMainCRTStartup)<br> 1000 base of code<br> 1000 base of data<br> <strong><span style="color:#FF0000">400000 image base (00400000 to 00428FFF)</span></strong><br> 1000 section alignment<br> 200 file alignment<br> 5.01 operating system version<br> 0.00 image version<br> 5.01 subsystem version<br> 0 Win32 version<br> 29000 size of image<br> 400 size of headers<br> 0 checksum<br> 2 subsystem (Windows GUI)</p> </td> </tr> </tbody> </table> 32 位映像的 ImageBase 都被设为 **0x00400000**,而 64 位映像的 ImageBase 被设为 **0x00000001\_40000000** ### 1.2 映像内的地址使用 ### 下面是从 ***helloworld.exe*** 映像中的 **.text** 节摘下来的数据: <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start; border:1px dotted rgb(204,204,204); table-layout:fixed"> <tbody> <tr> <td style="word-wrap:break-word"> <p> 00411490: 6A 64 68 00 72 41 00 6A 67 8B 45 08 50 <strong><span style="color:#0000FF">FF 15 C0</span></strong> jdh.rA.jg.E.P?.à<br> 004114A0: <strong><span style="color:#0000FF">83 41 00</span></strong> 3B F4 E8 D2 FC FF FF 8B F4 6A 64 68 38 .A.;?èòü??.?jdh8</p> </td> </tr> </tbody> </table> 注意上面的蓝色粗体部分,实际上这是一条 **call** 指令的机器代码,这条指令是: <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start; border:1px dotted rgb(204,204,204); table-layout:fixed"> <tbody> <tr> <td style="word-wrap:break-word"> <p><span style="color:#FF0000"><strong>0041149D</strong></span>: FF 15 C0 83 41 00 <strong><span style="color:#0000FF">call dword ptr [004183C0h]</span></strong></p> </td> </tr> </tbody> </table> 实际上,这就是调用 **LoadString()** 函数的一条指令,**LoadString()** 的地址就放在 **0x004183C0** 地址上。 当映像被加载后的 **ImageBase** 还是 **0x00400000**,那么这个映像就不需要 **ImageBase 重定位**,但是很遗憾,特别是当 32 位程序在 64 位系统上运行时,这个情况就发生。 ### 1.3 ImageBase 重定位 ### 在我的实例中,这一次 ***helloworld.exe*** 的运行,**ImageBase** 被加载到 **0x012b0000**,没错就需要进行 ImageBase 重定位处理。 <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start; border:1px dotted rgb(204,204,204); table-layout:fixed"> <tbody> <tr> <td style="word-wrap:break-word"> <p><strong><span style="color:#0000FF">call dword ptr [004183C0h]</span></strong></p> </td> </tr> </tbody> </table> 这个情况下,这个 **0x004183C0** 地址就会产生错误,加载器需要将它重新重位在:**0x012C83C0** 地址上。 这个 **0x012C83C0** 是等于:**0x004183C0 - 0x00400000 + 0x012b0000** = **0x012C83C0** 计算方法就是得到基于 ImageBase 的偏移量再加上新的 ImageBase 值,这个 **0x012C83C0** 就是正确的函数地址: <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start; border:1px dotted rgb(204,204,204); table-layout:fixed"> <tbody> <tr> <td style="word-wrap:break-word"> <p><strong>012C14B9</strong> FF 15 C0 83 2C 01 call dword ptr [__imp__LoadStringW@16 <strong><span style="color:#FF0000">(12C83C0h</span></strong>)] </p> </td> </tr> </tbody> </table> 上面就是 visual studio 2010 调试下得出的 call 指令 ## 2. .reloc 节 ## 现在转入正题,看看 ***helloworld.exe*** 映像的 **.reloc** 节,如下表: <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start"> <tbody> <tr> <td> <div> <strong>域</strong> </div> </td> <td> <div> <strong>.reloc 节</strong> </div> </td> </tr> <tr> <td>VirtualSize</td> <td> <div> 0x00000564 </div> </td> </tr> <tr> <td>VirtualAddress</td> <td> <div> 0x00028000 </div> </td> </tr> <tr> <td>SizeOfRawData</td> <td> <div> 0x00000600 </div> </td> </tr> <tr> <td>PointerToRawData</td> <td> <div> 0x00015400 </div> </td> </tr> <tr> <td>PointerToRelocations</td> <td> <div> 0 </div> </td> </tr> <tr> <td>PointerToLinenumbers</td> <td> <div> 0 </div> </td> </tr> <tr> <td>NumberOfRelocations</td> <td> <div> 0 </div> </td> </tr> <tr> <td>NumberOfLinenumbers</td> <td> <div> 0 </div> </td> </tr> <tr> <td>Characteristics</td> <td> <div> 0x42000040 </div> </td> </tr> </tbody> </table> ***helloworld.exe*** 的 **.reloc** 位置在 **0x00428000**(ImageBase + VritualAddress),它在映像文件的位置是 **0x00015400** 占用 **0x600 bytes** 的文件空间 ## 3. base relocation table ## <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start"> <tbody> <tr> <td> <div> <strong>域</strong> </div> </td> <td> <div> <strong>base relocation bale</strong> </div> </td> </tr> <tr> <td> <div> VirtualAddress </div> </td> <td> <div> 0x00028000 </div> </td> </tr> <tr> <td> <div> size </div> </td> <td> <div> 0x340 </div> </td> </tr> </tbody> </table> **base relocation table** 存放在 **.reloc** 节里,大小为 0x340 bytes base relocation table 由 **IMAGE\_BASE\_RELOCATION** 结构和它的 **Entry** 组成 ### 3.1 IMAGE\_BASE\_RELOCATION 结构 ### 这个结构在 **WinNT.h** 的定义为: <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start; border:1px dotted rgb(204,204,204); table-layout:fixed"> <tbody> <tr> <td style="word-wrap:break-word"> <p>//<br> // Based relocation format.<br> //</p> <p>typedef struct _IMAGE_BASE_RELOCATION { <br> DWORD VirtualAddress;<br> DWORD SizeOfBlock;<br> // WORD TypeOffset[1];<br> } IMAGE_BASE_RELOCATION;<br> typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;</p> </td> </tr> </tbody> </table> **VirtualAddress** 是 base relocation table 的位置,它是一个 RVA 值,**SizeOfBlock** 是 Base Relocation Table 的大小 ### 3.2 Entry 结构 ### Entry 结构只有一个 **WORD** 值,它紧跟着 **IMAGE\_BASE\_RELOCATION** 结构后面,但是这个 **WORD** 却分为两个部分: <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start"> <tbody> <tr> <td> <div> <strong>位域</strong> </div> </td> <td> <div> <strong>位</strong> </div> </td> <td> <div> <strong>长度</strong> </div> </td> <td> <div> <strong>描述</strong> </div> </td> </tr> <tr> <td> <div> Type </div> </td> <td> <div> [15:12] </div> </td> <td> <div> 4 Bits </div> </td> <td> <div> 高 4 位用来表示 Base Relocation Table 的类型 </div> </td> </tr> <tr> <td> <div> Offset </div> </td> <td> <div> [11:0] </div> </td> <td> <div> 12 Bits </div> </td> <td> <div> 低 12 位是 RVA 值,指出需要重定位的位置 </div> </td> </tr> </tbody> </table> 这个 **12** 位的 Offset 值是基于 **IMAGE\_BASE\_RELOCATION** 结构的 **VirtualAddress**, 而 VirtualAddress 是基于 ImageBase 的 RVA 值 因此最终的 Offset 值应该是 **ImageBase + VirtualAddress + Offset** 在 **WinNT.h** 中定义了 Base Relocation Table 的类型: <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start; border:1px dotted rgb(204,204,204); table-layout:fixed"> <tbody> <tr> <td style="word-wrap:break-word"> <p>//<br> // Based relocation types.<br> //</p> <p>#define IMAGE_REL_BASED_ABSOLUTE 0<br> #define IMAGE_REL_BASED_HIGH 1<br> #define IMAGE_REL_BASED_LOW 2<br> #define IMAGE_REL_BASED_HIGHLOW 3<br> #define IMAGE_REL_BASED_HIGHADJ 4<br> #define IMAGE_REL_BASED_MIPS_JMPADDR 5<br> #define IMAGE_REL_BASED_MIPS_JMPADDR16 9<br> #define IMAGE_REL_BASED_IA64_IMM64 9<br> #define IMAGE_REL_BASED_DIR64 10</p> </td> </tr> </tbody> </table> 大部分的 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 ## <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start; border:1px dotted rgb(204,204,204); table-layout:fixed"> <tbody> <tr> <td style="word-wrap:break-word"> <p>00428000 00 10 01 00 // VirtualAddress = 0x00011000<br> 00428004 DC 00 00 00 // SizeOfBlock = 0x000000DC</p> <p><br> // Entries</p> <p>00428008 93 34 // type = 3, offset = 493<br> 0042800A 9F 34 // type = 3, offset = 49F <br> 0042800C AF 34 // type = 3, offset = 4AF<br> 0042800E BB 34 // type = 3, offset = 4BB<br> 00428010 F4 34 // type = 3, offset = 4F4 <br> 00428012 10 35 // type = 3, offset = 510 <br> 00428014 2F 35 // type = 3, offset = 52F <br> 00428016 46 35 // type = 3, offset = 546 <br> 00428018 59 35 // type = 3, offset = 559 <br> 0042801A 6F 35 // type = 3, offset = 56F <br> 0042801C 94 35 // type = 3, offset = 594<br> 0042801E A0 35 // type = 3, offset = 5A0</p> <p><br> ... ...</p> <p> </p> <p><span style="color:rgb(255,0,0); font-weight:bold">004280DC</span> 00 20 01 00 // VirtualAddress = 0x00012000<br> 004280E0 20 01 00 00 // SizeOfBlock = 0x00000120</p> <p>004280E4 0C 30 // type = 3, offset = 00C <br> 004280E6 15 30 // type = 3, offset = 015 <br> 004280E8 1E 30 // type = 3, offset = 01E <br> 004280EA 23 30 // type = 3, offset = 023 <br> 004280EC 4D 30 // type = 3, offset = 04D <br> 004280EE 57 30 // type = 3, offset = 057</p> <p>... ...</p> </td> </tr> </tbody> </table> 第 1 个 base relocation table 的 size 是 0xDC bytes,因此,下一个 base relocation table 就在 **0x004280DC** 处 下面是使用 dumpbin 得出的 base relocation table 结果: <table style="color:rgb(0,0,0); font-family:Simsun; text-align:start; border:1px dotted rgb(204,204,204); table-layout:fixed"> <tbody> <tr> <td style="word-wrap:break-word"> <p>BASE RELOCATIONS #7<br> 11000 RVA, DC SizeOfBlock<br> 493 HIGHLOW 00417200 <a href="mailto:?szTitle@@3PA_WA" rel="nofollow">?szTitle@@3PA_WA</a> (wchar_t * szTitle)<br> 49F HIGHLOW 004183C0 <a href="mailto:__imp__LoadStringW@16" rel="nofollow">__imp__LoadStringW@16</a><br> 4AF HIGHLOW 00417138 <a href="mailto:?szWindowClass@@3PA_WA" rel="nofollow">?szWindowClass@@3PA_WA</a> (wchar_t * szWindowClass)<br> 4BB HIGHLOW 004183C0 <a href="mailto:__imp__LoadStringW@16" rel="nofollow">__imp__LoadStringW@16</a><br> 4F4 HIGHLOW 004183C4 <a href="mailto:__imp__LoadAcceleratorsW@8" rel="nofollow">__imp__LoadAcceleratorsW@8</a><br> 510 HIGHLOW 004183C8 <a href="mailto:__imp__GetMessageW@16" rel="nofollow">__imp__GetMessageW@16</a><br> 52F HIGHLOW 004183CC <a href="mailto:__imp__TranslateAcceleratorW@12" rel="nofollow">__imp__TranslateAcceleratorW@12</a><br> 546 HIGHLOW 004183D0 <a href="mailto:__imp__TranslateMessage@4" rel="nofollow">__imp__TranslateMessage@4</a><br> 559 HIGHLOW 004183D4 <a href="mailto:__imp__DispatchMessageW@4" rel="nofollow">__imp__DispatchMessageW@4</a><br> 56F HIGHLOW 00411590<br> 594 HIGHLOW 00411598<br> 5A0 HIGHLOW 004115A4</p> <p><br> ... ...</p> <p> 12000 RVA, 120 SizeOfBlock<br> C HIGHLOW 00417734 ___native_startup_state<br> 15 HIGHLOW 00417734 ___native_startup_state<br> 1E HIGHLOW 00415618 ___xi_z<br> 23 HIGHLOW 0041530C ___xi_a<br> 4D HIGHLOW 0041733C<br> 57 HIGHLOW 00417734 ___native_startup_state</p> </td> </tr> </tbody> </table> 与 dumpbin 的结果是相符的。 -------------------- ### 版权 mik 所有,转载请注明出处 ###
还没有评论,来说两句吧...