C++ __usercall hooking

3.4k views Asked by At

Hello in IDA i have a function

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

And i would like to hook/call it from my C++ injected dll This is how I have tried to call it but .exe crashes

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

   }
}

And this is how the exe calls this function

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

Few times in function there appears to be

add     esp, 24h
retn    10h

Which would mean there are more arguments or IDA got wrong argument types?

1

There are 1 answers

3
Captain Obvlious On

__userpurge functions use a calling convention similar to __usercall except that the caller is responsible for cleaning up the stack. However looking at the additional code you have posted IDA may very well be providing an incorrect number of parameters and an incorrect calling convention. I suggest that you verify this by placing a breakpoint at the location of call CALL_ORGIGINAL and watch the value of ESP before and after the call. If ESP is different when it returns then CALL_ORIGINAL is cleaning up the stack and there is nothing more for you to do. If CALL_ORIGINAL does clean up the stack you can likely determine the number of parameters passed by dividing the difference by 4 (assuming each parameter is 32bits).

Another problem is you should not be pushing eax onto the stack (according to the calling code included in your edit). The existing code that calls this function places the first parameter in eax but does not push it onto the stack.

Based on the code in your question and assuming the number of parameters is correct your hook function should look something like the example below.

__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
   }
}

If the calling convention and number of parameters is correct ESP should be the same value before and after the all to CALL_ORIGINAL. If it's not you will need to investigate it a bit more to determine the correct calling convention and parameters.

In short, never trust what IDA unless you verify it yourself.