【发布时间】:2014-11-05 01:01:47
【问题描述】:
我正在研究 C++ 和 ASM 中的钩子,目前我刚刚制作了一个简单的内联钩子,它在目标函数的第一条指令中放置一个跳转,在这种情况下是 OutputDebugString,仅用于测试目的。
问题是我的钩子在经过大约 3 天的研究并弄清楚了事情是如何工作的细节和平静之后终于工作了,但是有一个问题我不知道如何更改进入我的“假人”的参数" 函数,然后跳到原始函数的其余部分。
正如你在我的代码中看到的那样,我试图在 C++ 中简单地更改参数,但当然这不起作用,因为我之后会弹出所有寄存器:/
无论如何这里是我的虚拟函数,它是挂钩函数跳转到的:
static void __declspec(naked) MyDebugString(LPCTSTR lpOutputString) {
__asm {
PUSHAD
}
//Where i suppose i could run my code, but not be able to interfere with parameters :/
lpOutputString = L"new message!";
__asm {
POPAD
MOV EDI, EDI
PUSH EBP
MOV EBP, ESP
JMP Addr
}
original_DebugString(lpOutputString);
}
我明白为什么代码不能像我说的那样工作,我只是看不到适当的解决方案,非常感谢任何帮助。
【问题讨论】:
-
你需要将你的参数移动到工作寄存器,做一个 ADD 来做必要的改变,然后再次移动到你将用于函数参数的位置。
-
在纯汇编语言中,您通常在寄存器中传递参数。当将汇编与 C(或其他)混合时,您处理传递的参数,因为该语言认为适合传递它们。在这种情况下,它可能在堆栈上(就在返回地址下方)。也就是说,您的代码似乎没有任何实际意义。
-
我建议你只用一些参数和局部变量创建一个 c/c++ 函数,例如
__stdcall约定,并在反汇编器中查看编译器生成的 asm 代码如何与参数和局部堆栈变量交互并从中学习。它使用了一个简单的技巧,不必总是计算有多少push*/pop*s。 -
另外,如果你真的不想处理每个初学者在被编译器帮助你的所有漂亮的 c/c++ 魔法宠坏后所经历的 asm 地狱:如果你挂钩一个函数,并且您知道该函数的确切原型(包括调用约定),您可以给您的钩子函数提供完全相同的原型并在函数体中编写 100% c/c++(因此,摆脱
__declspec(naked))