Winapi 为什么通过内联程序集向函数传递参数不是';不一致?

Winapi 为什么通过内联程序集向函数传递参数不是';不一致?,winapi,assembly,visual-c++,x86,calling-convention,Winapi,Assembly,Visual C++,X86,Calling Convention,我从原始函数跳转到钩子,钩子运行执行函数的程序集。我试图将参数从原始函数传递到函数mWSARecv 我是这样做的: void mWSARecv(LPWSABUF lpBuffers) { std::cout << "WSARecv: " << lpBuffers->buf << " Len: " << lpBuffers->len << std::endl; } __declspec(naked) int hook

我从原始函数跳转到钩子,钩子运行执行函数的程序集。我试图将参数从原始函数传递到函数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;
    }
}
void mWSARecv(LPWSABUF lpBuffers)
{
默认情况下(不覆盖调用约定),以下为调用约定:

void mWSARecv(LPWSABUF lpBuffers)
{
    std::cout << "WSARecv: " << lpBuffers->buf << " Len: " << lpBuffers->len << std::endl;
}
由于
mWSARecv
是CDECL,因此在调用后必须清除推送的参数。如果不清除,则意味着当
popfd
和后续堆栈操作发生时,它们都将从堆栈上的错误位置恢复。在这种情况下,要清除推送的一个4字节参数的堆栈,需要向ES添加4个参数P。修复程序如下所示:

    push[ebp + 0x24];
    call mWSARecv;
    add esp, 4;
    popfd;
默认情况下(不覆盖调用约定),以下为调用约定:

void mWSARecv(LPWSABUF lpBuffers)
{
    std::cout << "WSARecv: " << lpBuffers->buf << " Len: " << lpBuffers->len << std::endl;
}
由于
mWSARecv
是CDECL,因此在调用后必须清除推送的参数。如果不清除,则意味着当
popfd
和后续堆栈操作发生时,它们都将从堆栈上的错误位置恢复。在这种情况下,要清除推送的一个4字节参数的堆栈,需要向ES添加4个参数P。修复程序如下所示:

    push[ebp + 0x24];
    call mWSARecv;
    add esp, 4;
    popfd;

如果
mWSARecv
是CDECL调用约定,则调用者必须清理堆栈。使用
push[ebp+0x24]推送4个字节
所以你必须在之后向esp添加4。也许在调用mWSARecv
@MichaelPetch之后放置
添加esp,4
,谢谢!如果mWSARecv将是STDCALL,它应该自动清理堆栈,对吗?在这种情况下,不需要添加4?另外,请你解释一下,为什么我必须在STDCALL中向堆栈指针添加4您调用的函数将清理传递的参数堆栈。在CDECL中,责任由调用该函数的人承担。如果
mWSARecv
是CDECL,则push[ebp+0x24]推送的4个字节;必须由您清理(使用类似于
add esp,4
)的内容。无法将4添加到esp(在本例中)意味着当mWSARecv返回时,它将执行
popfd
popad
,但堆栈上的所有内容都被移位4,这意味着由这两条指令还原的所有内容都已损坏。@MichaelPetch非常感谢,现在更有意义了!:)如果
mWSARecv
是CDECL调用约定,则调用方必须清理stack、 使用
push[ebp+0x24]推送4个字节
所以你必须在之后向esp添加4。也许在调用mWSARecv@MichaelPetch之后放置
添加esp,4
,谢谢!如果mWSARecv将是STDCALL,它应该自动清理堆栈,对吗?在这种情况下,不需要添加4?另外,请你解释一下,为什么我必须在STDCALL中向堆栈指针添加4您调用的函数将清理传递的参数堆栈。在CDECL中,责任由调用该函数的人承担。如果
mWSARecv
是CDECL,则push[ebp+0x24]推送的4个字节;必须由您清理(使用类似于
add esp,4
)的内容。无法将4添加到esp(在本例中)这意味着当mWSARecv返回时,它将执行
popfd
popad
,但堆栈上的所有内容都被移位了4,这意味着由这两条指令恢复的所有内容都已损坏。@MichaelPetch非常感谢,现在变得更有意义了!:)再次感谢,谢谢!我还有一个问题,是不是[ebp+0x24]参数的位置并不总是相同?@J.Doe参数的位置将始终位于CA:LL指令本身推送的返回地址之前的堆栈上。参数推送到堆栈上的物理地址可能会根据程序本身而变化。可能我还没有完全理解您的新问题n尽管如此。谢谢,这就解释了。出现的问题也是因为参数偏移量不总是相同的。一次是0x24,另一次是0x23。你知道我如何检测这样的更改吗?谢谢!你使用的是父函数的
ebp
,而不是设置自己的堆栈帧。这不一定有任何原因t要保持一致,至少它将取决于调用WSARecv的函数。请阅读与
esp
相关的参数,这将是一致的。再次感谢您,谢谢!不过我还有一个问题,可能是[ebp+0x24]参数的位置并不总是相同?@J.Doe参数的位置将始终位于CA:LL指令本身推送的返回地址之前的堆栈上。参数推送到堆栈上的物理地址可能会根据程序本身而变化。可能我还没有完全理解您的新问题n尽管如此。谢谢,这就解释了。出现的问题也是因为参数偏移量不总是相同的。一次是0x24,另一次是0x23。你知道我如何检测这样的更改吗?谢谢!你使用的是父函数的
ebp
,而不是设置自己的堆栈帧。这不一定有任何原因t要保持一致,至少取决于调用WSARecv的函数。请阅读与
esp
相关的参数,这将是一致的。