Pepsi_1
Pepsi_1

Reputation: 121

Hooking a usercall function from ida pro

int CachedTag_NoCache_GetTagPos( CEntity* centity, int tag, Vector* worldpos )
    {
        void* funccall = (void*)0x7D5BD0;
        __asm {
            mov edi, worldpos
            mov esi, centity
            push tag
            call funccall
            add esp, 4
        }
    }

Function crashes at add esp, 4....

I know its crashing from the clean up of this inline assembly. I just don't know how to fix it.

This is what is inside ida pro:

int __usercall sub_7A7D20<eax>(int a1<ecx>, int a2<edi>, int a3<esi>, int a4)
{
  int v4; // eax@2
  int result; // eax@2
  char *v6; // eax@3
  char v7; // al@5
  int v8; // [sp+0h] [bp-4h]@1

  v8 = a1;
  if ( *(_WORD *)(a3 + 678) == 1 )
  {
    LOBYTE(v8) = sub_5BB6F0(*(_BYTE *)(a3 + 4), *(_DWORD *)(a3 + 0x1E8));
    v4 = sub_7A7C40();
    result = sub_4DA2F0(a3, a2, a4, v4, v8);
  }
  else
  {
    v6 = sub_615EA0(*(_DWORD *)(a3 + 0x1E8), *(_BYTE *)(a3 + 4));
    result = sub_4B2F50(a3, v6, a2, a4);
  }
  if ( !result )
  {
    v7 = sub_624C70(a2, 0);
    result = sub_627380(1, "AimTarget_GetTagPos: Cannot find tag [%s] on entity\n", v7);
  }
  return result;
}

The assembly for this function from ida pro in text:

.text:007D5BD0 sub_7D5BD0      proc near               ; CODE XREF: sub_4DA2F0+76p
.text:007D5BD0                                         ; sub_62AE20+18p
.text:007D5BD0
.text:007D5BD0 arg_0           = dword ptr  4
.text:007D5BD0
.text:007D5BD0                 movzx   eax, byte ptr [esi+4]
.text:007D5BD4                 mov     ecx, [esi+1E8h]
.text:007D5BDA                 push    ebx
.text:007D5BDB                 mov     ebx, [esp+4+arg_0]
.text:007D5BDF                 push    eax
.text:007D5BE0                 push    ecx
.text:007D5BE1                 call    sub_615EA0
.text:007D5BE6                 add     esp, 8
.text:007D5BE9                 test    eax, eax
.text:007D5BEB                 jnz     short loc_7D5C00
.text:007D5BED                 fld     dword ptr [esi+30h]
.text:007D5BF0                 pop     ebx
.text:007D5BF1                 fstp    dword ptr [edi]
.text:007D5BF3                 fld     dword ptr [esi+34h]
.text:007D5BF6                 fstp    dword ptr [edi+4]
.text:007D5BF9                 fld     dword ptr [esi+38h]
.text:007D5BFC                 fstp    dword ptr [edi+8]
.text:007D5BFF                 retn
.text:007D5C00 ; ---------------------------------------------------------------------------
.text:007D5C00
.text:007D5C00 loc_7D5C00:                             ; CODE XREF: sub_7D5BD0+1Bj
.text:007D5C00                 push    edi
.text:007D5C01                 push    ebx
.text:007D5C02                 push    eax
.text:007D5C03                 push    esi
.text:007D5C04                 call    sub_4B2F50
.text:007D5C09                 add     esp, 10h
.text:007D5C0C                 test    eax, eax
.text:007D5C0E                 jnz     short loc_7D5C2B
.text:007D5C10                 push    eax
.text:007D5C11                 push    ebx
.text:007D5C12                 call    sub_624C70
.text:007D5C17                 push    eax             ; char
.text:007D5C18                 push    offset aCachedtag_noca ; "CachedTag_NoCache_GetTagPos: Cannot fin"...
.text:007D5C1D                 push    1               ; int
.text:007D5C1F                 call    sub_627380
.text:007D5C24                 add     esp, 14h
.text:007D5C27                 xor     eax, eax
.text:007D5C29                 pop     ebx
.text:007D5C2A                 retn
.text:007D5C2B ; ---------------------------------------------------------------------------
.text:007D5C2B
.text:007D5C2B loc_7D5C2B:                             ; CODE XREF: sub_7D5BD0+3Ej
.text:007D5C2B                 mov     edx, dword_D4F178
.text:007D5C31                 mov     eax, [edx+40688h]
.text:007D5C37                 pop     ebx
.text:007D5C38                 retn
.text:007D5C38 sub_7D5BD0      endp
.text:007D5C38
.text:007D5C38 ; ---------------------------------------------------------------------------
.text:007D5C39                 align 10h
.text:007D5C40

The assembly that I have is working. I enter into the game and it shows me what I want for about 3 minutes. Then it crashes. While having visual studio attached to the process it always says crashed on my function above at add esp, 4.

Now on a usercall that uses edi and esi do I have to pop them off after calling my function and/or do I have to retn something too?

Its obviously not fine the way I have it because it only works for about 3 minutes. The longest I had the code working for was about 3 games. Which were about 10 minutes in length.

Then after those 3 games it just started to fatal error on me.

Thanks for anyone who has the knowledge to answer this question.

I know its something stupid with the clean up after that function call in the inline assembly.

Upvotes: 1

Views: 3319

Answers (2)

Necrolis
Necrolis

Reputation: 26181

you need to save and restore EDI and ESI (the x86 ABI defines them as non-volatile registers, which means you cannot trash them), it also likely the prologue and epilogue generated by MSVC that is causing issues, IMO, it would be better to write this a a pure naked function, this gives you better control over the assembly generated, and ensures you can properly emulated non-standard (optimized) calling conventions:

__declspec(naked) int __fastcall CachedTag_NoCache_GetTagPos(CEntity* centity, int tag, Vector* worldpos)
{
    __asm {
        push edi
        push esi
        mov edi,worldpos
        mov esi,centity
        push tag
        mov eax,0x7D5BD0
        call eax
        add esp,4
        pop esi
        pop edi
        retn 4
    }
}

In terms of the exception you are getting, it sounds like you aren't getting the correct line, an assembly level debugger like ollydbg would help you pin-point the exact cause and the correct location.


Also, as a word of caution, never use a fixed address, use a relocation safe variant, ie: a base address + RVA; in my above code, you need only alter two lines to achieve that:

mov eax,[base_address]
add eax,rva

where base_address is along the lines of:

UINT_PTR base_address = (UINT_PTR)GetModuleHandle("some_module");

and is globally accessible.

Upvotes: 1

typ1232
typ1232

Reputation: 5607

The code you provided is correct. The target function itself is stack neutral and you clean your pushed parameter after calling.

Are you sure that this is the correct line the code is crashing at? What exception do you get? I don't think that adding a constant to a register can even cause an exception.

The crash intervals you report seem random. This could be a threading issue that you for example pass an invalid CEntity and the called function crashes. You can prevent this by hooking the thread that usually calls this function and call it within that thread.

Upvotes: 0

Related Questions