Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Calling client function from c++ or CE

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming
View previous topic :: View next topic  
Author Message
sullx
Cheater
Reputation: 0

Joined: 03 Jan 2013
Posts: 37

PostPosted: Sun Jul 27, 2014 6:24 pm    Post subject: Calling client function from c++ or CE Reply with quote

The client of the application I am reversing has a function known as GetObjectFromID which returns a pointer to an object and takes as input parameters an integer ID. I have found this function in ollydbg, and what I am trying to understand is how I can call this function from c++ (or CE). This is how the code gets called in the actual client

Code:
.text:00714288                 mov     ecx, [ebx+8]
.text:0071428B                 push    eax //object ID
.text:0071428C                 mov     eax, [ecx]
.text:0071428E                 mov     edx, [eax+8]
.text:00714291                 call    edx //Vfunc call to retrieve some pointer needed for GetObjectByID
.text:00714293                 mov     esi, eax // pass said pointer as param in esi register
.text:00714295                 call    GetObjectByID


Someone I talked to said that this should be easily callable if:
Pointer in ecx : ecx = [[[["Client.exe"+0x6BF530]+0x4]+0x7C]+0x94]+0xB4

But I don't understand where this nested chain of pointers is coming from, nor how that actually calls the function as I don't see how any arguments could be pushed on to the stack with this method.


In hope of simplifying this I have written my own Crackme app with a function that I want to be able to call from a separate program that I attach.

For CE my thought would be to auto-assemble a jmp to my own code where I would back up the state of the registers, then set eax to my own argument and push it to the stack; then call the function, get the return value, then reset the registers back to what they were and then call the function again with the original values. Is there a better way to do this in CE?

And how about in c++?
Back to top
View user's profile Send private message
661089799107
Expert Cheater
Reputation: 3

Joined: 25 Jan 2009
Posts: 186

PostPosted: Sun Jul 27, 2014 8:58 pm    Post subject: Reply with quote

sullx wrote:
I don't see how any arguments could be pushed on to the stack with this method.


Keep in mind that call itself does not pop the stack arguments afterwards. It has to either be done by the caller (example: add esp, 4), or by the called function (ret 4, or restore from saved value - mov esp, ebp).

This all depends on the calling convention that is used by the function.

So if the virtual function doesn't clean the stack then the arguments go straight to the next function.

sullx wrote:

[[[["Client.exe"+0x6BF530]+0x4]+0x7C]+0x94]+0xB4

Pointer in ecx : ecx = But I don't understand where this nested chain of pointers is coming from


The result of the nested pointers is the 'this' pointer. It should be the same value that ECX is after the following instruction:

Code:

mov     ecx, [ebx+8]


If you didn't have the pointer path then from here you would find out where 'EBX' is coming from, and where the value that writes to that is coming from, and so on. Eventually you would track it down to a static address: "Client.exe"+0x6BF530.

There are many different pointer paths that are valid so it may of been tracked down from a different function as well. Or even pointer scanned.

As for calling it in c++ it may look something like this:
Code:

// Make sure you replace __stdcall with the proper calling convention, you didn't show enough code for me to see what it actually was.
typedef void*(__stdcall *t_GetObjectByID)(int id);

// Replace 0x00000000 with the address of the game function
t_GetObjectByID GetObjectByID = 0x00000000;

int objectId = 0; // your id
void* objectPtr = GetObjectByID(objectId);
Back to top
View user's profile Send private message
sullx
Cheater
Reputation: 0

Joined: 03 Jan 2013
Posts: 37

PostPosted: Mon Jul 28, 2014 9:27 pm    Post subject: Reply with quote

Thanks for this.

So when I try to naively typedef the function pointer and then create a function of this type equal to an address I keep getting an error. I wrote a small crackme app with a simple global scope function to test this on. In the actual crackme app the function is called in this way:

Code:

011218B9   B8 01000000      MOV EAX,1
011218BE   85C0             TEST EAX,EAX
011218C0   74 53            JE SHORT function.01121915
011218C2   6A 00            PUSH 0  <<< single int argument
011218C4   E8 2CF8FFFF      CALL function.011210F5   <<< function call
011218C9   83C4 04          ADD ESP,4


I then try to write a dll to inject with the following, as per your suggestion:

Code:

typedef int(__stdcall* tFunction)(int param1);

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
  switch(ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
      int base;
      base = (ULONG)GetModuleHandleW(0);
      tFunction nFunction = base+0x110F5;

     // call function next

      break;

    case DLL_PROCESS_DETACH:
      break;
    }

  return TRUE;
}



But I get this compiler error:

Code:
error C2440: 'initializing' : cannot convert from 'int' to 'tFunction'
1>          Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
1>main.cpp(36): error C2360: initialization of 'nFunction' is skipped by 'case' label


What obvious mistake am I making here? Am I not setting the address but trying to assign a value?
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8587
Location: 127.0.0.1

PostPosted: Mon Jul 28, 2014 11:18 pm    Post subject: Reply with quote

You need to cast your pointer to the function type manually. Also you cannot initialize within a switch case like that unless you force a scope onto the given case.

So you would need something like this instead:
Code:
case DLL_PROCESS_ATTACH:
{
    auto funcAddr = (ULONG)GetModuleHandleW(0) + 0x110F5;
    ((tFunction*)funcAddr)(0x1234);
    break;
}


Also, your typedef should be:
Code:
typedef int(__stdcall tFunction)(int param1);

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
661089799107
Expert Cheater
Reputation: 3

Joined: 25 Jan 2009
Posts: 186

PostPosted: Tue Jul 29, 2014 2:18 am    Post subject: Reply with quote

Code:

011218C4   E8 2CF8FFFF      CALL function.011210F5   <<< function call
011218C9   83C4 04          ADD ESP,4


Note the ADD ESP, 4 after the function call (c/c++ default convention).

Quote:

The main characteristics of __cdecl calling convention are:

Arguments are passed from right to left, and placed on the stack.
Stack cleanup is performed by the caller.


Code:

typedef int(__cdecl *t_GetObjectByID)(int id);

t_GetObjectByID pGetObjectByID = reinterpret_cast<t_GetObjectByID>(base + 0x00000000);

int retVal = pGetObjectByID(0);


With the asterisks is fine.

Also you shouldn't call non kernel32 win32 functions inside DllMain. So make sure even your target function doesn't do that.

Create a new thread if you have to.

Quote:

Calling functions that require DLLs other than Kernel32.dll may result in problems that are difficult to diagnose. For example, calling User, Shell, and COM functions can cause access violation errors, because some functions load other system components. Conversely, calling functions such as these during termination can cause access violation errors because the corresponding component may already have been unloaded or uninitialized.
Back to top
View user's profile Send private message
sullx
Cheater
Reputation: 0

Joined: 03 Jan 2013
Posts: 37

PostPosted: Tue Jul 29, 2014 8:57 pm    Post subject: Reply with quote

Wonderful! This works great, thank you! So just a few updates so the whole story is here and a question about inline asm..

I updated the client program I was injecting into so that the function called in main was a method of myClass. In asm the caller looks like this:

Code:

00C91056   . 8B35 0020C900  MOV ESI,DWORD PTR DS:[<&KERNEL32.Sleep>]               
00C9105C   . 8D6424 00      LEA ESP,DWORD PTR SS:[ESP]
00C91060   > 6A 00          PUSH 0 
00C91062   . 8D4D FF        LEA ECX,DWORD PTR SS:[EBP-1]                 
00C91065   . E8 16020000    CALL function.myClass::GetObjectFromID                 
00C9106A   . 8B0D 5020C900  MOV ECX,DWORD PTR DS:[<&MSVCP100....$basic_ostream...>]
00C91070   . 51             PUSH ECX   



The dll I inject looks like this (note that the calling convention is now __stdcall as opposed to before when it was cdecl, because it appears in the asm the called function is doing the clean up):

Code:
 
typedef int(__stdcall* tFunction)(int param1);

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
  tFunction nFunction;
  int retval;
  int base;

  switch(ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
      base = (ULONG)GetModuleHandleW(0);
      cout << "base = "<< hex << base <<dec<<endl;
      cout << "function address = " << hex << base+0x1280 << dec << endl;
      nFunction = reinterpret_cast<tFunction>(base+0x1280);
      retval = nFunction(2112);
      cout << "I have a return value = " << retval << endl;
      break;

    case DLL_PROCESS_DETACH:
      break;
    }

  return TRUE;
}


Now, I should be able to achieve the same thing by using inline asm, but unfortunately when I make a similar dll, it never makes it passed the call statement:

Code:

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
  int base;
  int retval;

  switch(ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
      base = (ULONG)GetModuleHandleW(0);
      cout << "base = "<< hex << base <<dec<<endl;
      cout << "function address = " << hex << base+0x1280 << dec << endl;
      __asm {
        push 8;
        call base+0x1280;
        mov [retval],eax;
      }
      cout << "I have a return value = " << retval << endl;
      break;

    case DLL_PROCESS_DETACH:
      break;
    }

  return TRUE;
}


Any idea why it's hanging here?
Back to top
View user's profile Send private message
661089799107
Expert Cheater
Reputation: 3

Joined: 25 Jan 2009
Posts: 186

PostPosted: Wed Jul 30, 2014 1:41 am    Post subject: Reply with quote

The stack cleanup is indeed done by the called function, but since it is a class function it actually uses the __thiscall convention.

Code:

Thiscall is the default calling convention for calling member functions of C++ classes (except for those with a variable number of arguments).

The main characteristics of thiscall calling convention are:

Arguments are passed from right to left, and placed on the stack. this is placed in ECX.
Stack cleanup is performed by the called function.


With class functions there is a hidden paramter. The this pointer.

So your typedef should actually look like:

Code:

// Can change MyClass* to void* or DWORD if the class isn't yours
typedef int(__thiscall* tFunction)(MyClass* This, int param1);


If the real GetObjectByID uses that ECX register then it is probably a __thiscall.

Code:

typedef int(__thiscall *t_GetObjectByID)(void* This, int id);
Back to top
View user's profile Send private message
sullx
Cheater
Reputation: 0

Joined: 03 Jan 2013
Posts: 37

PostPosted: Wed Jul 30, 2014 9:03 am    Post subject: Reply with quote

Ah, I see. And I assume that the reason that the function call still worked with my other typedef (with __stdcall and without the object pointer) was because the function was simple and didn't depend on any of the class members or methods.

Any idea on how I can do this with inline assembler? Still having issues with it.
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8587
Location: 127.0.0.1

PostPosted: Wed Jul 30, 2014 12:04 pm    Post subject: Reply with quote

sullx wrote:
Ah, I see. And I assume that the reason that the function call still worked with my other typedef (with __stdcall and without the object pointer) was because the function was simple and didn't depend on any of the class members or methods.

Any idea on how I can do this with inline assembler? Still having issues with it.


In some cases you may run into issues casting directly as __thiscall. Instead you can just use __fastcall and be sure to pass the 'this' pointer as the first param.
For example, I get this issue from time to time when hooking onto class functions inside of various MMORPGs.

Code:
extern "C"
{
    char (__fastcall* Real_SomeClassFunction)(LPVOID pThisPtr, LPVOID lpUnknown, char* pszText, int nUnknown); = 0;
}


Then later in the code Real_SomeClassFunction is set via detouring or setting it via a cast to a raw pointer.

And is there any reason you need to do this with inline asm vs. just doing it with C style casting? If it works already with the C casting, why bother writing it in inline asm?

But if you still feel the need for it, don't calculate the address during the call, that is where its failing. Instead, put the address of the function into a variable and use the variable as the address like this:

Code:
auto address = base+0x1280;

__asm
{
    push 8
    call [address]
    mov retval, eax
}

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites