为什么通过内联汇编将参数传递给函数不一致?
Why passing arguments to function via inline assembly isn't consistent?
我有一个从原始函数到我的挂钩的跳转,它运行执行一个函数的程序集。我正在尝试将参数从原始函数传递给函数 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.
第一跳:
装配钩子:
我做错了什么?
默认情况下(不覆盖调用约定)以下是 CDECL 调用约定:
void mWSARecv(LPWSABUF lpBuffers)
{
std::cout << "WSARecv: " << lpBuffers->buf << " Len: " << lpBuffers->len << std::endl;
}
根据调用约定,MSDN 文档说:
Stack-maintenance responsibility - Calling function pops the arguments from the stack.
这与 STDCALL 不同,后者具有此参数清理规则:
Stack-maintenance responsibility - Called function pops its own arguments from the stack.
考虑到这一点,您的代码中的问题在 hookWSARecv
这些行中:
push[ebp + 0x24];
call mWSARecv;
popfd;
因为mWSARecv
是CDECL所以你push的参数在调用之后要清理。不这样做意味着当 popfd
和后续堆栈操作发生时,它们将从堆栈上的错误位置恢复。在这种情况下,要清理推送的一个 4 字节参数的堆栈,您需要在调用后将 4 添加到 ESP。修复看起来像:
push[ebp + 0x24];
call mWSARecv;
add esp, 4;
popfd;
我有一个从原始函数到我的挂钩的跳转,它运行执行一个函数的程序集。我正在尝试将参数从原始函数传递给函数 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.
第一跳:
装配钩子:
我做错了什么?
默认情况下(不覆盖调用约定)以下是 CDECL 调用约定:
void mWSARecv(LPWSABUF lpBuffers)
{
std::cout << "WSARecv: " << lpBuffers->buf << " Len: " << lpBuffers->len << std::endl;
}
根据调用约定,MSDN 文档说:
Stack-maintenance responsibility - Calling function pops the arguments from the stack.
这与 STDCALL 不同,后者具有此参数清理规则:
Stack-maintenance responsibility - Called function pops its own arguments from the stack.
考虑到这一点,您的代码中的问题在 hookWSARecv
这些行中:
push[ebp + 0x24];
call mWSARecv;
popfd;
因为mWSARecv
是CDECL所以你push的参数在调用之后要清理。不这样做意味着当 popfd
和后续堆栈操作发生时,它们将从堆栈上的错误位置恢复。在这种情况下,要清理推送的一个 4 字节参数的堆栈,您需要在调用后将 4 添加到 ESP。修复看起来像:
push[ebp + 0x24];
call mWSARecv;
add esp, 4;
popfd;