我一直在尝试挂钩一个大多数由编译器优化的函数,它在调用之前初始化EAX,并将其返回值存储在EAX中。
这里有一些代码,
mov eax,dword ptr ds:[0xA6DD08]
push 0x3DC
add eax,0x800
call 0x48A2B4
mov esi,eax
起初,0xA6DD08是指向内存中某些数据的指针,但是一旦添加0x800,EAX仅指向zero的值,但是接下来的几个DWORD存储指针或数据数组的指针。函数本身的目的是查找并返回一个特定对象,该对象的DWORD变量等于给定的0x3DC。
[当使用__ asm从我的dll调用该函数时,它工作正常,但我试图用c ++编写它,类似
Class1* pClass = reinterpret_cast<Class1*(__stdcall*)(DWORD)>(0x48A2B4)(988);
我相信,根据我的阅读,只有__ stdcall使用EAX来存储它的返回值,这就是为什么我选择__ stdcall调用约定的原因,但我不理解EAX]的目的在调用函数之前。
除非EAX是被调用函数的输入,否则add eax,0x800
之前的[call
是没有意义的。
[在EAX中传递1 arg,然后在堆栈中传递另一个args对我来说就像GCC的regparm=1
calling convention。或者,如果在此之前设置了其他规则,则regparm=1
以EAX,EDX和ECX的顺序传递。
Linux内核的32位x86构建通常是用regparm=3
构建的,但是用户空间GNU / Linux代码通常遵循笨拙的旧i386 System V约定,该约定将堆栈中的所有args传递。
根据-mregparm=3
,其他一些晦涩的调用约定也在EAX中传递了第一个参数:
仅__stdcall使用EAX来存储其返回值
实际上,all
x86调用约定对整数args进行了全面的处理。同样是x86-64约定。请参阅register
调用约定指南。