运行时调用指令改变

逆向工程 部件 x86 C++
2021-06-28 23:44:43

在调试和逆向工程我的 exe 时,我发现了一件非常奇怪的事情。

call ds:GetModuleFileNameA

此调用指令由 IDA 中的以下十六进制字节组成。

FF 15 24 C0 41 00

(我认为 0x41C024 表示导入表的索引)

但是当我在调试时查看这个调用指令时,它看起来如下。

FF 15 24 C0 1A 00

(当然,image base 从 400000 变成了 190000)

但我不明白的是操作系统(我使用 win10)如何自动更改代码区域中的所有偏移量。

有人可以解释一下吗?

1个回答

它被称为重定位
每个可执行文件都有一个名为 .reloc 的部分

此部分包含有关在图像库更改时需要修补的所有地址的详细信息

加载器使用这个部分来改变所有修改过的基地址

例如 win7 x86 32 位 calc.exe

从 cdb.exe 反汇编(随机图像库)

002616a3 ff15f4132600    call    dword ptr [calc!_imp__LoadStringW (002613f4)]

从 dumpbin 反汇编(默认镜像库)

C:\>dumpbin  /nologo c:\Windows\System32\calc.exe /disasm /range:0x10016A2,0x10016b1

  010016A2: 50                 push        eax
  010016A3: FF 15 F4 13 00 01  call        dword ptr [__imp__LoadStringW@16]

如果您查看 .reloca 部分,您会注意到地址6A5的 HIGHLOW 条目

Offset(h) 00 01

000B9C00  00 10  ..
000B9C02  00 00  ..
000B9C04  B4 00  ´.
000B9C06  00 00  ..
000B9C08  41 36  A6
000B9C0A  52 36  R6
000B9C0C  A5 36  ¥6 <<<<<
000B9C0E  B3 36  ³6

所以加载器可以修补 RVA 处的地址(ImageBase + 节基址 + 地址)

imagebase = 0x1000000 + base of section = 0x1000 + HIGHLOW address = 6a5 
= 0x10016a5

在这个地址 dumpbin 有F4 13 00 01 而 cdb 有f4 13 26 00

加载程序已根据映像库对其进行修补

我的这篇文章有更多关于修补内容的详细信息

更新wrt评论一些exe没有.reloc

是的,完全有可能在没有 reloc 的情况下使用 exe,
事实上如果通过,则有一个 msvc 链接器开关 /FIXED 会产生没有重定位的 exe

在大多数情况下,exe 无需重定位即可存活,因为它们是第一个加载到进程地址空间中的,
因此它们总是倾向于获得首选的 ImageBase

重定位对 Dll 最重要,尤其是那些动态加载或作为对另一个 dll 的依赖项加载的 dll

在这种情况下,可能会发生冲突,操作系统需要一种机制来重新定位有问题的二进制文件

如果 Windows 无法重新定位 dll,它会导致应用程序崩溃

C:\>cdb -c "!error c0000018;q" cdb | tail -n 3
0:000> cdb: Reading initial command '!error c0000018;q'
Error code: (NTSTATUS) 0xc0000018 (3221225496) - {Conflicting Address Range}  The specified address range conflicts with
 the address space.
quit: