【问题标题】:Understanding a function call that uses EAX before and after for the return value了解在返回值之前和之后使用 EAX 的函数调用
【发布时间】:2020-06-04 16:39:35
【问题描述】:

我一直在尝试挂钩一个主要由编译器优化的函数。它在调用之前初始化 EAX,并将其返回值存储在 EAX 中。

这是一些代码:

mov eax,dword ptr ds:[0xA6DD08]
push 0x3DC                     
add eax,0x800                  
call 0x48A2B4  
mov esi,eax     

起初,0xA6DD08 是指向内存中某些数据的指针,但是一旦添加 0x800,EAX 只指向 的值,但接下来的几个 DWORD(s)存储指针或数据数组的指针。该函数本身的目的是查找并返回一个特定对象,该对象的 DWORD 变量等于给定值 0x3DC。

当使用 __asm 从我的 dll 调用函数时,它可以完美运行,但我正在尝试用 c++ 编写它,类似于

Class1*  pClass = reinterpret_cast<Class1*(__stdcall*)(DWORD)>(0x48A2B4)(988);

我相信从我读到的只有 __stdcall 使用 EAX 来存储它的返回值,这就是我选择 __stdcall 调用约定的原因。我不明白的是调用函数之前 EAX 的目的。

【问题讨论】:

  • 1) 为什么这个问题被标记为“C++”? 2) 为什么你想用内联 ASM 写东西,而不是用更高级的语言表达你想要的东西,让编译器为 ASM 操心? - 就生成最佳 ASM 而言,您很少能超越优化编译器(即使可以,在任何实际应用程序中,性能方面通常都无关紧要)。
  • 我不想做编译器所做的事情,我只是想用我的 DLL 中的 c++ 代码正确地挂钩函数。
  • 你检查过函数本身的目标代码吗? EAX 的期望是什么?
  • 我做了,正如我所说,它只是指向内存中的一个位置,它的值只是零。但是它自己的函数在 EAX 之后使用数据,我认为它更像是指针指针或指针数组。基本上功能目的是在列表或smth中查找对象
  • 对于 32 位编译器来说,期望 eaxedxecx 中的前几个参数并不罕见,假设它们适合 fast 调用约定。

标签: c++ assembly visual-c++ x86 calling-convention


【解决方案1】:

call 之前的add eax,0x800 没有意义,除非 EAX 是被调用函数的输入。

在 EAX 中传递 1 个参数,在堆栈中传递另一个参数在我看来就像 GCC 的 regparm=1 calling convention。或者,如果在此之前设置了其他 reg,regparm=3 会传入 EAX、EDX 和 ECX(按此顺序)。

Linux 内核的 32 位 x86 版本通常使用 -mregparm=3 构建,但用户空间 GNU/Linux 代码通常遵循笨拙的旧 i386 System V 约定,该约定传递堆栈上的所有参数。

根据https://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions,其他一些晦涩的调用约定也在 EAX 中传递了第一个参数:

  • Delphi 和 Free Pascal register:EAX、EDX、ECX(从左到右的 Pascal 样式 arg 传递,我猜是 EAX 中最右边的 arg?不像 GCC regparm)
  • Watcom 编译器:EAX、EDX、EBX、ECX。除非您在推送堆栈 arg 之前遗漏了一些 EDX、EBX 和 ECX 设置,否则我们可以排除这种情况。

只有 __stdcall 使用 EAX 来存储它的返回值

实际上,所有 x86 调用约定对整数 args 全面执行此操作。还有两个 x86-64 约定。请参阅Agner Fog's 调用约定指南。

【讨论】:

  • 恐怕这里不是这样,我的 dll 和目标 exe 都是用 Visual c++ (MSVC) 编译的,而 regparm 不是一个选项。经过更多挖掘,我有点确定 0xA6DD08 指向地图对象并添加 eax,0x800 只是将 eax 获取到特定地图以开始查找。
  • @Muhab:好的,所以 Visual C++ 无法生成与您的 DLL 使用的调用约定兼容的 asm。太糟糕了。 :/ 您的选择是 MSVC 内联汇编,或将编译器切换到 GCC、clang 或 ICC,以便您可以在该函数上使用 __attribute__((regparm(1)))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-01
  • 2017-04-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-08
  • 2020-11-09
相关资源
最近更新 更多