Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding pointer with 'find out what writes to this address' strange offset

I'm trying to find a base pointer for UrbanTerror42. My setup is as followed, I have a server with 2 players. cheat-engine runs on client a. I climb a ladder with client b and then scan for incease/decrease. When I have found the values, I use find out what writes to this address. But the offset are very high and point to empty memory. I don't really know how to proceed

For the sake of clarity, I have looked up several other values and they have the same problem

I've already looked at a number of tutorials and forums, but that's always about values where the offsets are between 0 and 100 and not 80614.

I would really appreciate it if someone could tell me why this happened and what I have to do/learn to proceed.

enter image description here

enter image description here

thanks in advance

like image 658
Jan-Fokke Avatar asked Mar 26 '18 21:03

Jan-Fokke


People also ask

How do I do a pointer scan?

You can open the pointer scanner with Memory View->Tools->Pointer scan, or by right-clicking on an address in the address list and choose "Pointer scan for this address". If you use the first method, you can use File->Open to open a saved pointer list or you can use the Pointer scanner->Scan for pointer option.


1 Answers

Urban Terror uses the Quake Engine. Early versions of this engine use the Quake Virtual Machine and the game logic is implemented as bytecode which is compiled into assembly by the Quake Virtual Machine. Custom allocation routines are used to load these modules into memory, relative and hardcoded offsets/addresses are created at runtime to accommodate these relocations and do not use the normal relocation table method of the portable executable file format. This is why you see these seemingly strange numbers that change every time you run the game.

The Quake Virtual Machines are file format .qvm and these qvms in memory are tracked in the QVM table. You must find the QVM table to uncover this mystery. Once you find the 2-3 QVMs and record their addresses, finding the table is easy, as you're simply doing a scan for pointers that point to these addresses and narrowing down your results by finding those which are close in memory to each other.

The QVM is defined like:

struct vmTable_t
{
    vm_t vm[3];
};

struct vm_s {
    // DO NOT MOVE OR CHANGE THESE WITHOUT CHANGING THE VM_OFFSET_* DEFINES
    // USED BY THE ASM CODE
    int         programStack;       // the vm may be recursively entered
    intptr_t(*systemCall)(intptr_t *parms);

    //------------------------------------

    char        name[MAX_QPATH];

    // for dynamic linked modules
    void        *dllHandle;
    intptr_t     entryPoint;           //(QDECL *entryPoint)(int callNum, ...);
    void(*destroy)(vm_s* self);

    // for interpreted modules
    qboolean    currentlyInterpreting;

    qboolean    compiled;
    byte        *codeBase;
    int         codeLength;

    int         *instructionPointers;
    int         instructionCount;

    byte        *dataBase;
    int         dataMask;

    int         stackBottom;        // if programStack < stackBottom, error

    int         numSymbols;
    struct vmSymbol_s   *symbols;

    int         callLevel;      // counts recursive VM_Call
    int         breakFunction;      // increment breakCount on function entry to this
    int         breakCount;

    BYTE        *jumpTableTargets;
    int         numJumpTableTargets;
};
typedef struct vm_s vm_t;

The value in EAX in your original screenshot should be the same as either the codeBase or dataBase member variable of the QVM structure. The offsets are just relative to these addresses. Similarly to how you deal with ASLR, you must calculate the addresses at runtime.

Here is a truncated version of my code that does exactly this and additionally grabs important structures from memory, as an example:

void OA_t::GetVM()
{
    cg = nullptr;
    cgs = nullptr;
    cgents = nullptr;
    bLocalGame = false;
    cgame = nullptr;

    for (auto &vm : vmTable->vm)
    {
        if (strstr(vm.name, "qagame")) { bLocalGame = true; continue; }

        if (strstr(vm.name, "cgame"))
        {
            cgame = &vm;
            gamestatus = GSTAT_GAME;
            //char* gamestring = Cvar_VariableString("fs_game");

            switch (cgame->instructionCount)
            {
            case 136054: //version 88
                cgents = (cg_entities*)(cgame->dataBase + 0x1649c);
                cg = (cg_t*)(cgame->dataBase + 0xCC49C);
                cgs = (cgs_t*)(cgame->dataBase + 0xf2720);
                return;

Full source code for reference available at OpenArena Aimbot Source Code, it even includes a video overview of the code.

Full disclosure: that is a link to my website and the only viable resource I know of that covers this topic.

like image 135
GuidedHacking Avatar answered Oct 18 '22 04:10

GuidedHacking