C++ , Cheat Engine / OllyDBG finding base "static" address from multi-level pointers

14,915

I think you are misunderstanding the goal of Cheat Engine.

CE allows you to modify values that are stored in a durable way in memory. For example, on the heap, or in the program's static data.

For example, C++ objects are allocated in a deterministic way, and hence, they never move. This is why they can be referenced by a pointer that remains constant all over the object's lifetime. This object is sometime owned by another. If you find a pointer to the owner object, you found what is called a base pointer.

For example :

class Object
{
    bool dummy;
    int someField;
    Object* child;
};

Now imagine you have a nested tree of 3 Object. Meaning that you have a root Object (n°1), whose child is another Object (n°2), whose child is another Object (n°3). Imagine you do something like this :

int main(int argc, char** argv)
{
    Object root; // n°1
    root.child = new Object(); // n°2
    root.child->child = new Object(); // n°3

    return 0;
}

You're interested in messing with n°3's someField value. You know that the address of someField, relative to an Object, is of +sizeof(bool) = 1. So (void*)&(object n°3) + 1 is a pointer to the someField you want.

Now, how do you find a pointer to object n°3 ? Knowing that the relative address of child is +sizeof(bool)+sizeof(int) = 5. We know that a pointer to object n°3 is (void*)&(object n°2) + 5.

Same goes for the address of object n°2, I'll leave that as an exercise.

But what about object n°1 ? It's not allocated on the heap. It's on the stack. Crap. So we must find another way to find the address where object n°1 is stored.

Local variables are stored on the stack. In assembly, they are identified by their offset relative to the register EBP (or ESP if the function does not change the stack). EBP is the top of the stack, while ESP is the bottom of the stack.

In this example :

function foo()
{
    int a;
    double b;
}

When foo is called, the stack will be increased just enough to hold a and b, that is, sizeof(int) + sizeof(double), or 12 bytes. a will be stored at EBP - sizeof(int) = EBP - 4 (same as ESP + 8) and b will be stored at EBP - sizeof(int) - sizeof(double) = EBP - 12 (same as ESP). Attention! The compiler can change this order, so the declaration order of your variables isn't necessarily the same in memory. Optimizations can also change this completely. But let's keep this simple okay ?

So back to our main example. What local variables do we have ? root only. Therefore root will be located at EBP - 9 directly. But this, ONLY when main is the function on top of the call stack. Without a debugger, you can't do it.

Let's assume that our EBP is 0028FF28 when main is called (taken from a freshly compiled C program).

root is then at (0x0028FF28 - 9) = 0x0028FF1F; the pointer to root.child is at (0x0028FF1F + 5) = (0x0028FF24); Therefore, root.child is located at *0x0028FF24.

The pointer to root.child->child is at (*0x0028FF24 + 5) = (let's say 10000) Then root.child->child is at *10000.

Finally, root.child->child.someField is at *10000 + 3.

To sum up: you just need to find the static address of root to find the rest. root is NOT on the heap or any kind of durable memory, but it is on main's stack, which lasts during almost all the program, so it's almost as if it were permanent. CE helps you find a static address by scanning the entire process memory space

With all this in mind, you should be able to calculate hp's relative address on the stack and find a static pointer to it (main is very, very, very likely to have a static frame address every time you launch the program). If you need help, use a debugger ! I recommend Immunity Debugger.

Share:
14,915
Christian
Author by

Christian

Updated on June 22, 2022

Comments

  • Christian
    Christian about 2 years

    I'm back again, frustrated and desperately searching for help :D.

    I am trying to create a cheat for a simple program, it's basically going to be a .dll file which will change an integer's value from the main program when it's injected to it using its base address. The thing is, I can't find it using cheat engine mainly because there are multiple level pointers with NEGATIVE? offsets. for example:

    //Starting pointer address
    0x0033FCF0 -> 200
    
    //Finding second level pointer using "Find out what's accessing this address" in Cheat Engine
    **(mov eax,[ebp+08])** // **EAX=0x00000007** , **EPB=0x0033FCE8 => mov 00000007,[0033FCE8+08]**
    
    2nd Level Pointer:
    **(0033FCE8+18) -> 200**
    

    So I proceed to find the next pointer using "Find out what's .... " but while using T-SEARCH with the second-level pointers address and i get like 7 - 8 new static addresses.

    The thing is, I cannot tell which one is correct because cheat engine REFUSES to let me add a pointer using a NEGATIVE? offset.

    Example:

    Base Pointer:
    **mov eax,[epb-18] !!!** // Notice the **MINUS**
    

    And on top of everything Cheat Engine refuses to accept a pointer with a negative offset!

    So , is there another way of finding the base address from multiple level pointers? OlyDBG / Idapro solutions are welcome. Thanks alot guys!

    Here's the source code of the simple program I'm trying to hack:

    #include <iostream>
    #include <conio.h>
    #include <windows.h>
    #include <stdlib.h>
    
    int main(){
        int hp = 100;
        while(1){
            std::cout << hp << std::endl;
            Sleep(3000);
            hp += 10;
            system("cls");
        }
        return 0;
    }
    

    What i am trying to do is edit the hp integer with this .dll

    #include <windows.h>
    #define BASE    0xBASE_POINTERS_ADDRESS_WHICH_I_NEED_TO_FIND
    #define OFFSET  0xTHE_OFFSET
    #define VALUE   90
    void MainFunction()
    {
          while(1)
          {
                if (GetAsyncKeyState(VK_MENU)&0x8000 && GetAsyncKeyState('C')&0x8000) 
                MessageBox(0,L"Alt + C was pressed!",L"MessageBox! ",0);
                *(int*)((*(int*)BASE) + OFFSET) = VALUE;
    
                Sleep(100); //Let the program rest, otherwise it hogs cpu resources.
          }
    }
    
    BOOL WINAPI DllMain(HINSTANCE MyInstance,DWORD reason_for_call,LPVOID PointerToVoid)
    {
             if (reason_for_call == DLL_PROCESS_ATTACH) CreateThread(0,0,(LPTHREAD_START_ROUTINE)&MainFunction,0,0,0);
             return true;
    }
    

    By the way i am trying to hack the hp! ~ Oh , wait , i already said that , oh well , whatever ;)

    Thank you guys, god bless you all!