C++ __usercall hooking



Hello在IDA中我有一个函数

void __userpurge Test(int a1<eax>, int a2, int a3, int a4, char a5)

我想钩/调用它从我的c++注入的dll这就是我试图调用它的方式,但是。exe崩溃了

DWORD CALL_ORIGINAL = 0x00EAF6D0;
__declspec(naked) void  myHookedFunc(int a1,int a2,int a3,int a4,char a5) {
    __asm
 {
    push a5
    push a4
    push a3
    push a2
    push eax
    call  CALL_ORGIGINAL //maybe use JMP?
    retn
   }
}

exe就是这样调用这个函数的

mov     eax, [ebp+arg_4]
add     esp, 8
push    eax
push    ecx
mov     ecx, [edi+2138h]
mov     edx, [ecx+4]
mov     ecx, [edx+30h]
mov     edx, [ecx]
mov     eax, esp
mov     [eax], edx
mov     eax, [edi+20h]
mov     [esp+40h+var_24], esp
push    eax
push    eax
mov     eax, edi
call    Test
pop     edi
pop     esi  
retn

函数中有几次出现

add     esp, 24h
retn    10h

这意味着有更多的参数或IDA得到错误的参数类型?

__userpurge函数使用类似于__usercall的调用约定,只是调用方负责清理堆栈。但是,查看您发布的IDA的附加代码很可能提供了错误数量的参数,以及不正确的调用约定。我建议您通过在call CALL_ORGIGINAL的位置放置一个断点来验证这一点,并在调用前后观察ESP的值。如果ESP在返回时不同,则CALL_ORIGINAL正在清理堆栈,并且没有更多的事情要做。如果CALL_ORIGINAL确实清理了堆栈,你可以通过将差值除以4来确定传递的参数数量(假设每个参数都是32位)。

另一个问题是您不应该将eax压入堆栈(根据编辑中包含的调用代码)。调用该函数的现有代码将第一个形参放在eax中,但没有将其压入堆栈。

根据你的问题中的代码,假设参数的数量是正确的,你的钩子函数应该看起来像下面的例子。

__declspec(naked) void  myHookedFunc(int a1,int a2,int a3,int a4,char a5) {
    __asm
 {
    push a5
    push a4
    push a3
    push a2
    // eax is not pushed onto the stack
    call CALL_ORGIGINAL
    retn
   }
}

如果呼叫约定和参数个数正确,ESP在all到CALL_ORIGINAL之前和之后应该是相同的值。如果不是,则需要进一步研究以确定正确的调用约定和参数。

总之,永远不要相信IDA,除非你自己验证过。

最新更新