Search code examples
c++cassemblyhookusercall

Is my stdcall wrapper for usercall function correct?


I need to wrap the below __usercall function to _cdecl/_stdcall:

char __usercall sub_4017B0<al>(int a1<ebx>, int a2)

a1 is integer, a2 is actually an arry of ints ('int args[10]')

Is this correct? What does the <al> mean behind sub_4017B0 ?

int __stdcall func_hook_payload(int callnum, int* args);

// Wrapper for
// char __usercall sub_4017B0<al>(int callnum<ebx>, int a2)
__declspec(naked) void func_hook()
{__asm{
    push ebp
    mov ebp, esp

    push dword ptr[ebp + 0x28] // args[9]
    push dword ptr[ebp + 0x24] // args[8]
    push dword ptr[ebp + 0x20] // args[7]
    push dword ptr[ebp + 0x1C] // args[6]
    push dword ptr[ebp + 0x18] // args[5]
    push dword ptr[ebp + 0x14] // args[4]
    push dword ptr[ebp + 0x10] // args[3]
    push dword ptr[ebp + 0x0C] // args[2]
    push dword ptr[ebp + 0x08] // args[1]
    push dword ptr[ebp + 0x04] // args[0]
    push ebx // callnum
    call func_hook_payload
    leave
    ret // note: __usercall is cdecl-like
}}

How would a wrapper look like for calling sub_4017B0 ?
The wrapper should have this signature:

int sub_4017B0_wrapper(int callnum, int* args);

Solution

  • does the function take an actual int* or does it take va_args? in cases like this you need to provide the original calling code to.

    from what I can gather, your wrapper should look like this(I don't use stack frames, but your frame is wrong as you don't pop ebp before returning):

    __declspec(naked) void func_hook()
    {
        __asm
        {
            push dword [esp + 4]    //int* - pArgs
            push ebx                //int - nArgs
            call func_hook_payload  //you can even just jump to this, the stack should clean itself up correctly
            retn
        }
    }
    

    should it be va_args you can do something like this:

    __declspec(naked) void func_hook()
    {
        __asm
        {
            lea eax,[esp + 4]       //int* - &nArg[0]: here we abuse the way the windows stack grows, creating a stack based buffer 
            push eax                //int* - pArgs
            push ebx                //int - nArgs
            call func_hook_payload
            retn
        }
    }
    

    Calling the old func is pretty simple too, you can do it without a nake function, but really I prefer naked funcs :)

    void __declspec(naked) __stdcall CallTheOldVMFunc(int nArgs, int* pArgs)
    {
        __asm
        {
            push ebx                //save ebx, its not a scratch register
            mov ebx,[esp + 8]       //set the number of args
            push [esp + 12]         //push the arg ptr
            call TheOldVMFunc
            pop ebx                 //restore ebx
            retn 8                  //ret and cleanup
        }
    }