DLL引入表重定位 .reloc

   前几天日,在做彩虹显IP补丁程序的时候,需要将原格式化字符串从"%d.%d.*.*"修改成"%d.%d.%d.%d"以使其能显示完整的IP,在补丁代码中需要引用该字符串,于是直接从原代码中copy了一段引用该字符串的代码。头几天还能正常工作,不知什么原因程序突然无法运行了,打开调试器跟踪才发现问题就出在对字符串的引用上,模块载入后的基址与前几天相比发生了改变,补丁中对字符串的引用指向了一个无效空间,但是原代码中对字符串的引用却能修正到正确地址空间上。于是,我看到了“奇怪”的现象:相同的二进制代码却能导致不同运行结果。

    虽然绕道解决了该字符串调用的问题,但是没弄懂其中原因始终觉得不爽,于是决定写点代码实验一下。写一个空的DLL,在DllMain()中添加一条OutputDebugString("BB7887"),然后写一个可执行程序用LoadLibrary()载入该DLL文件,为了使“同一个”DLL能加载到多个地址空间,最简单的方法就是将该DLL文件复制为多个DLL文件然后在可执行程序中多次加载,呵呵,偷个懒!用OllyDbg跟踪,得到的结论是,无论该DLL被加载到任何基址上,原代码中对字符串的引用能成功,但相同的以补丁方式修改的代码,只有在DLL加载到默认的0x10000000基址上能正确引用字符串外,其余的都指向了无效空间。……Google之后才认识到,PE文件在被载入时可以根据基地址对代码中的地址进修修正,也就是“重定位”。所以虽然同样是push xxxx却能有不同的结果,原代码中的push xxxx可以被修正为push bbbb,其中bbbb = xxxx + aaaa,aaaa为DLL模块的基址,而补丁中的push xxxx就没这么幸运了,没人来管这个后娘养的孩子,xxxx被直接入栈。

    重定位的基本原理:重定位以来与PE头文件的.reloc段,该段以索引的方式指出代码段中所有需要修正的数的地址,该地址以RVA相对虚地址的方式来表示,即该数值表示到基地址的偏移量。.reloc段由一系列子项组成,每项的数据结构如下:
DWORD VirtualAddress ;    起始 RVA 值,每一个偏移位置必须加上此值才能够构成一个真正的 RVA
DWORD SizeOfBlock ;       该项的总长
WORD offset[n] ;            偏移地址,只用到该字的低12bits,高4bits为标志为,一般为3
如:
Offset        0  1  2   3   4   5   6  7  8   9   A  B   C  D   E  F   Ascii
00000000  00 10 00 00 60 00 00 00 35 30 43 30 5F 30 80 30  ...`...50C0_0€0
00000010  8C 30 92 30 9C 30 AE 30 B8 30 BE 30 D2 30 D8 30  ????????
00000020  F0 30 F5 30 FC 30 03 31 0A 31 17 31 32 31 38 31  ???1.112181
00000030  3E 31 44 31 4A 31 50 31 5E 31 66 31 6C 31 77 31  >1D1J1P1^1f1l1w1
00000040  84 31 8C 31 9A 31 9F 31 A4 31 A9 31 B4 31 C1 31  ????????
00000050  CB 31 E0 31 EC 31 F2 31 14 32 26 32 82 32 9E 32  ????2&2??
对应于:
->Relocation Directory
   1. Relocation Block:
    VirtualAddress:  0x00001000  (".text")
    SizeOfBlock:     0x00000060  (0x002C block entries)
    RVA        Type
    ---------- -----------------
    0x00001035 HIGHLOW
    0x00001043 HIGHLOW
    0x0000105F HIGHLOW
    0x00001080 HIGHLOW
    0x0000108C HIGHLOW
    0x00001092 HIGHLOW
    0x0000109C HIGHLOW
    0x000010AE HIGHLOW
    0x000010B8 HIGHLOW
    0x000010BE HIGHLOW

    在上面的例子中,所能表示的最大偏移仅仅为0x1ffff,远远是不够用的,所以.reloc段通常是由多个偏移索引的子项组成的,每个子项只能负责0x1000范围内的偏移量,每个子项以0x1000来分段对齐,比如,要指出RVA为0x43569865处的数据需重定位,那么VirtualAddress = 0x43569000,其中某索引的值offset = 0x865 or 0x3000 = 0x3865 。

    用LordPE查看一下,定有更深刻的认识。另外:被重定位的数据在OllyDbg中都以下划线的方式加以表示。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值