0
void __usercall sub_101A7850@<eax>(int a1@<edx>, int a2@<ecx>, int a3, int a4, int a5, int a6)

My first attempt (crashes):

__declspec(naked) void __stdcall callit(const int& a1, const int& a2, unsigned int a3, const int *a4, int a5, int *a6)
    {
        // void __usercall sub_101A7850@<eax>(int a1@<edx>, int a2@<ecx>, int a3, int a4, int a5, int a6)
        __asm
        {
            mov ecx, [esp + 4] // a1
            mov edx, [esp + 8] // a2
            push [esp + 12] // a3
            push [esp + 16] // a4
            push [esp + 20] // a5
            push [esp + 24] // a6
            call funcaddr
            retn 24
        }
    }

I have verified funcaddr is valid. Pretty sure its a __fastcall

2
  • it might help us if you give a little more context - in which function does the crash occur, with what register values, etc. – peter ferrie Aug 31 '15 at 22:18
  • Do you have some asm code where this function is called? Could you provide the assembly of the function? From the code snippet it looks like you're pushing the parameters in the wrong order. – Viktor Aug 31 '15 at 22:21
3

Just use something like this:

void call_sub_101A7850(int a1, int a2, int a3, int a4, int a5, int a6){
    uintptr_t addr = 0x101A7850;
    unsigned int result;
    __asm {
        mov edx, a1;
        mov ecx, a2;
        push a6;
        push a5;
        push a4;
        push a3;
        call addr;
        add esp, 16;
        mov result, eax;
    }
    return result;
}

It seems to be __fastcall; however, in that calling convention, the first argument is stored in ecx, and the second one in edx, not like in your function's prototype, so you'll have to swap arguments order, like this:

typedef int(__fastcall* tTheFunc)(int a1, int a2, int a3, int a4, int a5, int a6);
tTheFunc func = (tTheFunc) 0x101A7850;
func(a2, a1, a3, a4, a5, a6);
//   ^swapped order, because a fastcall will always put the first arg in ecx and second in edx

You can also call it directly, like this:

((int(__fastcall*)(int, int, int, int, int, int)) 0x101A7850)(a2, a1, a3, a4, a5, a6);

Here's what's wrong with your function:

  • Don't use naked functions to wrap assembly calls, you don't need it, and it just makes everything harder
  • You can directly do mov ecx, <argument-name> instead of guessing where is the variable on the stack -- mov ecx, a1 is much more intuitive, reliable and readable than mov ecx, [esp + 4]
  • You are doing a retn 24 to clear your own function's pushed arguments, but you're not clearing what you've pushed for the called function, i.e. 16 more bytes (4 args * 4 bytes)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.