【发布时间】:2014-09-01 12:36:13
【问题描述】:
我尝试挂钩一些函数,不管 x86 上是 __stdcall 还是 __cdecl。
我想做以下事情:
1. 保留堆栈
2. 保留去寄存器
3. 做我的事
4. 恢复寄存器
5. 恢复栈
我的堆栈没有问题,但我的寄存器备份确实有一些问题:如果不修改其中一些寄存器,我就无法备份寄存器(我不能使用堆栈,因为我无法以这种方式备份堆栈)!
我可以在堆上备份它们(我使用具有一些 .EAX 、 .EBX 等成员的结构),我从 ASM 访问该结构,这就是问题所在......我必须修改一些寄存器能够做到这一点!
然而,这是我的故事。我真正想了解的是以下问题的答案:
对于函数调用期间可以修改的寄存器和不修改的寄存器有什么“规则”吗?
我用调试器检查了一些函数调用。我在“调用 SomeFunction”处添加了一个断点,按 F8 键“跳过函数调用”并检查修改后的寄存器。我可以看到这样的东西: 1. ESP/EBP 可能会根据调用约定进行修改(cdecl vs stdcall) 2. EAX、EBX、EDX - 几乎总是被修改! 3. EBX、EDI、ESI 似乎总是被保留!
所以我的“伪解决方案”来了:如果我只保留那些寄存器(EBX、EDI、ESI)可以吗?我不会弄乱堆栈,所以 EBP 和 ESP 不是问题。但我必须修改一些寄存器(EAX、ECX、EDX)。
我对一些编译器优化有什么问题吗?是否可以通过修改那些“无辜”的寄存器来搞乱代码:EAX、ECX、EDX?
谢谢
【问题讨论】:
-
保留堆栈是什么意思?你并没有真正保存它,只是在你完成后恢复SP。
-
是的,我不修改 EBP,我修改但恢复 ESP。问题比我描述的要复杂。我只需要知道是否可以只保留这些寄存器:EBX、EDI、ESI。
-
@lonut 您必须保留所有寄存器。但我不明白你的问题,这听起来微不足道。
-
一个函数看起来像这样:push param;调用函数;调用将下一个 EIP 推入堆栈并转到该函数。 1. 在那个函数上,我跳转到我的代码(仅 asm 函数,裸) 2. 我必须调用一些函数并跳转到另一个函数(回调) 3. 回调函数必须具有调用前的堆栈(相同的原型) 4.回调函数执行后我必须有未修改的寄存器和堆栈
-
@lonut 抱歉,我还没有完全理解。你想做一些定制的事情还是什么?你不只是遵循调用约定并保持简单吗?
标签: assembly call cpu-registers