我从原始函数跳转到我的钩子,它运行执行函数的程序集。我正在尝试将原始函数中的参数传递给函数 mWSARecv 。
我是这样做的:
void mWSARecv(LPWSABUF lpBuffers)
{
std::cout << "WSARecv: " << lpBuffers->buf << " Len: " << lpBuffers->len << std::endl;
}
__declspec(naked) int hookWSARecv() // Original -> Here
{
__asm
{
pushad;
pushfd;
push[ebp + 0x24];
call mWSARecv;
popfd;
popad;
jmp WSARecvTramp;
}
}
然后我保存寄存器和标志。按下所需的参数[ebp + 0x24]并调用输出它们的函数。它工作一次,但下次它会导致执行。
原始函数调用约定是 __ stdcall 。
第一跳:
汇编挂钩:
我做错了什么?
答案 0 :(得分:4)
默认情况下(不覆盖调用约定),以下是CDECL调用约定:
void mWSARecv(LPWSABUF lpBuffers)
{
std::cout << "WSARecv: " << lpBuffers->buf << " Len: " << lpBuffers->len << std::endl;
}
根据调用约定,MSDN文档说:
堆栈维护责任 - 调用函数从堆栈中弹出参数。
这与具有此参数清除规则的STDCALL不同:
堆栈维护责任 - 被调用函数从堆栈中弹出自己的参数。
考虑到这一点,代码中的问题在hookWSARecv
这些行中:
push[ebp + 0x24];
call mWSARecv;
popfd;
因为mWSARecv
是 CDECL ,所以您推送的参数必须在通话后进行清理。如果不这样做,则意味着当popfd
和后续堆栈操作发生时,它们都将从堆栈中的错误位置恢复。在这种情况下,要清理一个4字节参数的堆栈,您需要在调用后向 ESP 添加4。该修复程序如下所示:
push[ebp + 0x24];
call mWSARecv;
add esp, 4;
popfd;