开发者

How do game trainers change an address in memory that's dynamic?

开发者 https://www.devze.com 2023-01-01 03:14 出处:网络
Lets assume I am a game and I have a global int* that contains my health. A game trainer\'s job is to modify this value to whatever in order to achieve god mode. I\'ve looked up tutorials on game trai

Lets assume I am a game and I have a global int* that contains my health. A game trainer's job is to modify this value to whatever in order to achieve god mode. I've looked up tutorials on game trainers to understand how they work, and the general idea is to use a memory scanner to try and find the address of a certain value. Then modify this address by injecting a dll or whatever.

But I made a simple program with a global int* an开发者_如何学编程d its address changes every time I run the app, so I don't get how game trainers can hard code these addresses? Or is my example wrong?

What am I missing?


The way this is usually done is by tracing the pointer chain from a static variable up to the heap address containing the variable in question. For example:

struct CharacterStats
{
    int health;
    // ...
}

class Character
{
public:
    CharacterStats* stats;

    // ...

    void hit(int damage)
    {
        stats->health -= damage;
        if (stats->health <= 0)
            die();
    }
}


class Game
{
public:
    Character* main_character;
    vector<Character*> enemies;
    // ...
}

Game* game;

void main()
{
    game = new Game();
    game->main_character = new Character();
    game->main_character->stats = new CharacterStats;

    // ...

}

In this case, if you follow mikek3332002's advice and set a breakpoint inside the Character::hit() function and nop out the subtraction, it would cause all characters, including enemies, to be invulnerable. The solution is to find the address of the "game" variable (which should reside in the data segment or a function's stack), and follow all the pointers until you find the address of the health variable.

Some tools, e.g. Cheat Engine, have functionality to automate this, and attempt to find the pointer chain by themselves. You will probably have to resort to reverse-engineering for more complicated cases, though.


Discovery of the access pointers is quite cumbersome and static memory values are difficult to adapt to different compilers or game versions.

With API hooking of malloc(), free(), etc. there is a different method than following pointers. Discovery starts with recording all dynamic memory allocations and doing memory search in parallel. The found heap memory address is then reverse matched against the recorded memory allocations. You get to know the size of the object and the offset of your value within the object. You repeat this with backtracing and get the jump-back code address of a malloc() call or a C++ constructor. With that information you can track and modify all objects which get allocated from there. You dump the objects and compare them and find a lot more interesting values. E.g. the universal elite game trainer "ugtrain" does it like this on Linux. It uses LD_PRELOAD. Adaption works by "objdump -D"-based disassembly and just searching for the library function call with the known memory size in it.

See: http://en.wikipedia.org/wiki/Trainer_%28games%29

Ugtrain source: https://github.com/sriemer/ugtrain

The malloc() hook looks like this:

static __thread bool no_hook = false;

void *malloc (size_t size)
{
    void *mem_addr;
    static void *(*orig_malloc)(size_t size) = NULL;

    /* handle malloc() recursion correctly */
    if (no_hook)
        return orig_malloc(size);

    /* get the libc malloc function */
    no_hook = true;
    if (!orig_malloc)
        *(void **) (&orig_malloc) = dlsym(RTLD_NEXT, "malloc");

    mem_addr = orig_malloc(size);

    /* real magic -> backtrace and send out spied information */
    postprocess_malloc(size, mem_addr);
    no_hook = false;

    return mem_addr;
}

But if the found memory address is located within the executable or a library in memory, then ASLR is likely the cause for the dynamic. On Linux, libraries are PIC (position-independent code) and with latest distributions all executables are PIE (position-independent executables).


EDIT: never mind it seems it was just good luck, however the last 3 numbers of the pointer seem to stay the same. Perhaps this is ASLR kicking in and changing the base image address or something?

aaahhhh my bad, i was using %d for printf to print the address and not %p. After using %p the address stayed the same

#include <stdio.h>

int *something = NULL;

int main()
{
    something = new int;
    *something = 5;

    fprintf(stdout, "Address of something: %p\nValue of something: %d\nPointer Address of something: %p", &something, *something, something);
    getchar();
    return 0;
}


Example for a dynamicaly allocated varible

The value I want to find is the number of lives to stop my lives from being reduced to 0 and getting game over.

  1. Play the Game and search for the location of the lifes variable this instance.
  2. Once found use a disassembler/debugger to watch that location for changes.
  3. Lose a life.
  4. The debugger should have reported the address that the decrement occurred.
  5. Replace that instruction with no-ops

Got this pattern from the program called tsearch


A few related websites found from researching this topic:

  • http://deviatedhacking.com/index.php?/topic/75-dynamic-memory-allocation/
  • http://www.edgeofnowhere.cc/viewforum.php?f=183
  • http://www.oldschoolhack.de/tutorials/Theories%20and%20methods%20of%20code-caves.htm
  • http://webcache.googleusercontent.com/search?q=cache:4wzMzFIZx54J:gamehacking.com/forums/tutorials-beginners/11597-c-making-game-trainer.html+reading+a+dynamic+memory+address+game+trainer&cd=2&hl=en&ct=clnk&gl=au&client=firefox-a (A google cache version)
  • http://www.codeproject.com/KB/cpp/codecave.aspx


The way things like Gameshark codes were figured out were by dumping the memory image of the application, then doing one thing, then looking to see what changed. There might be a few things changing, but there should be patterns to look for. E.g. dump memory, shoot, dump memory, shoot again, dump memory, reload. Then look for changes and get an idea for where/how ammo is stored. For health it'll be similar, but a lot more things will be changing (since you'll be moving at the very least). It'll be easiest though to do it when minimizing the "external effects," e.g. don't try to diff memory dumps during a firefight because a lot is happening, do your diffs while standing in lava, or falling off a building, or something of that nature.

0

精彩评论

暂无评论...
验证码 换一张
取 消