I am trying to call a function generated by Hex-Rays by injecting a DLL, but have so far only managed to crash the process.

This is the code generated by Hex-Rays

int __usercall sub_54C3A0@<eax>(int a1@<esi>, void *a2@<ecx>)
  char *v2; // eax@1
  char *v3; // edx@1
  char v4; // cl@2
  int result; // eax@4
  char v6[84]; // [sp+0h] [bp-58h]@1

  dword_81D7CC = 1;
  v2 = (char *)sub_431620(55);
  v3 = (char *)(v6 - v2);
    v4 = *v2;
    v2[(_DWORD)v3] = *v2;
  while ( v4 );
  sub_4330E0(*(_DWORD *)v6);
  dword_81D7CC = 0;
  result = 0;
  if ( v6[0] )
    dword_81DAE0 = 0;
    if ( sub_54C480(100, a1) || dword_81DAE0 || sub_54C480(75, a1) || dword_81DAE0 || sub_54C480(50, a1) )
      result = 1;
  return result;

And this is my code

static DWORD hook_address = 0x54C3A0;
__declspec(naked) int hook()
    __asm {
        push esi // a1
        push ecx // a2
        call hook_address
        retn 4

What would the correct wrapper look like, and why?

  • It should be mov esi, a1 , mov ecx, a2. Note that usercall is not actually any calling convention. It is a way of representing unknown/custom calling conventions. See this answer. – 0xec Oct 11 '15 at 16:11
  • I tried that, still get access violation. – Magnus von Wachenfeldt Oct 11 '15 at 17:41
  • Do it like this: mov esi, a1, mov ecx, a2, call hook_address, ret. Using retn 4 clears 4 bytes from the stack, but usercalls don't need it because their arguments are in registers, not in the stack. – rev Oct 11 '15 at 21:11
  • That worked. Also, the address was wrong all the time. After running the program from IDA the addresses updated. No wonder I got access violations all over the place. – Magnus von Wachenfeldt Oct 12 '15 at 11:00
  • 1
    @AcidShout can you write your comment as an answer so that this question can be marked answered, and also help others in future? – tmr232 Oct 13 '15 at 5:56

Your hook is wrong because retn 4 is for __stdcalls, not __usercalls, and because you must move arguments to registers, not push them. Do it like this:

mov esi, a1
mov ecx, a2
call hook_address

retn 4 would clean 4 bytes from the stack, but you didn't push anything, so it's not correct, which is why you use ret instead.

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.