游戏训练师如何更改内存中动态的地址?

Gam*_*WTF 12 pointers memory-address

让我们假设我是一个游戏,我有一个int*包含我健康的全局.游戏训练师的工作是将此值修改为任何内容以实现上帝模式.我已经查阅了游戏培训师的教程,以了解它们是如何工作的,一般的想法是使用内存扫描程序来尝试找到某个值的地址.然后通过注入一个dll或其他来修改这个地址.

但是我创建了一个简单的全局程序,int*每次运行应用程序时它的地址都会发生变化,所以我不知道游戏培训师如何对这些地址进行硬编码?或者我的例子错了吗?

我错过了什么?

Vla*_*eev 7

通常这样做的方法是将指针链从静态变量跟踪到包含相关变量的堆地址.例如:

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;

    // ...

}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果你遵循mikek3332002的建议并在Character :: hit()函数中设置一个断点并且删除减法,那么它将导致包括敌人在内的所有角色都是无懈可击的.解决方案是找到"游戏"变量的地址(应该驻留在数据段或函数的堆栈中),并按照所有指针直到找到运行状况变量的地址.

某些工具(例如Cheat Engine)具有自动执行此功能的功能,并尝试自行查找指针链.但是,对于更复杂的情况,您可能不得不采用逆向工程.

  • 非常好的例子,谢谢,所以所有游戏黑客都依赖于静态指针?这意味着指针链的根必须是静态的? (2认同)
  • 是的,如果它在数据段中(从源代码的角度来看是一个全局变量),并且如果我们不计算ASLR.它也可以是一个堆栈变量(例如main()中的局部变量),在这种情况下,它的地址可能因系统而异,你需要走栈才能找到它,这更复杂. (2认同)
  • 这很容易,只需根据模块加载的基地址计算新地址.例如,大多数可执行文件都与初始基址0x00400000链接.如果您在0x00543210处找到变量,并且模块已加载到0x76400000,那么该值将为0x76543210. (2认同)