为什么windows把标准函数的基地址放在数据段中?

逆向工程 拆卸 视窗
2021-06-16 06:24:08

从最近由 MSVC 编译的“HelloWorld.exe”的反汇编中:

.text:00411279                 call    ds:__imp__printf

那么,为什么基地址是数据段,而不是代码段(这样做更合乎逻辑?)

项目使用多线程调试 Dll 作为运行时库。

2个回答
  1. Windows 没有这样做;MSVC 编译器就是这样做的。
  2. 内容__imp__printf不是函数的代码;它是函数代码的指针。由于它是一个指针(它是数据,而不是代码),因此指针值位于数据段中而不是代码段中是有意义的。更具体地说,这个指针值是由加载器在运行时设置的,所以内存页需要是可写的,这更像是将它放在数据段而不是代码段中的一个原因。

ds:由IDA加入,而不是由编译器。如果查看原始操作码字节,您将看到指令中没有 DS 覆盖前缀。这样做很愚蠢。

IDA 添加了这个ds:前缀,否则你不会知道这是一个间接调用——也就是说,它正在读取一个名为地址的 32 位变量,__imp__printf然后调用存储在该变量中的地址。如果没有ds:,它将只是直接调用__imp__printf

如果 IDA 使用更好的汇编语言语法——即 nasm 语法——该指令看起来很简单,使用方括号表示它是内存读取(并dword与其他一些奇怪的 类型区分开来call):

.text:00411279             call dword [__imp__printf]

Windows 与几乎所有其他 32 位操作系统一样,具有扁平地址空间。CS、DS、ES 和 SS 都具有相同的基地址 0,因此您使用哪个段作为基地址并不重要。(除了如果 CS 是你的段,你不能进行内存写入。)FS 和 GS 有不同的基础,因为主要操作系统都将它们用于线程本地存储,但那些在指令中总是有明确的前缀字节。