C / C ++程序中如何存在静态地址?

我已经看了一下Cheat Engine ,它可以让你检查和操作Windows上正在运行的进程的内存:你根据它们的值扫描variables,然后你可以修改它们,例如在游戏中作弊。

为了编写一个机器人或类似的东西,你需要find一个你想改变的variables的静态地址,也就是说,如果这个进程重新启动,那么这个variables保持不变。 方法大致是这样的:

  1. 查找您感兴趣的variables的地址,按值查找
  2. 查找使用该地址的代码,例如查找它所属的结构的地址(因为结构偏移是固定的)
  3. find指向该指针的另一个指针,直到find一个带有静态地址的指针(在Cheat Engine中显示为绿色)

从我看过的教程看来,它工作得很好,但是我很难理解它为什么起作用。

不是所有的variables,包括全局静态variables,在运行时都会得到一个非常随机的地址吗?

奖金问题:

  1. Cheat Engine如何判断一个地址是否是静态的(即重启时会保持不变)?
  2. 一个教程提到,许多旧的和一些现代的游戏(如使命召唤4) 使用静态地址。 这怎么可能?

我将首先回答奖金问题,因为他们介绍了一些你可能需要知道的概念来理解主要问题的答案。

如果你知道一个可执行文件是如何工作的,那么回答第一个奖励问题是很容易的:所有的全局/静态变量都在.data节中,其中.exe存储节的地址偏移量,所以Cheat Engine只检查变量是否在这个地址范围内(从本节到下一节)​​。

对于第二个问题,可以只使用静态地址,但对于游戏几乎是不可能的。 即使是较老的。 教程创建者可能试图说的是,他想要的所有变量实际上都有一个指向它们的静态指针。 但仅仅是由于你创建了一个局部变量,或者甚至将一个参数传递给了一个函数,它们的值都被存储在堆栈中。 这就是为什么几乎不可能有一个“静态”的程序。 即使你编译一个实际上什么都不做的程序,它可能会有一些东西被存储在堆栈中。

对于整个问题本身,并不是所有的动态地址变量都是由全局变量指向的。 这完全取决于程序员。 例如,我可以创建一个局部变量,并且不会将其地址分配给C程序中的全局/静态指针。 在这种情况下找到这个地址的唯一方法就是在变量首次被分配给栈中的一个值的时候,实际上知道这个代码。

一些变量有一个动态地址,因为它们只是局部变量,它们在第一次被赋值给它们时被存储在栈中。

其他一些变量具有静态地址,因为它们被声明为编译器的全局变量或静态变量。 这些变量具有固定的地址偏移量,它是可执行文件中.data部分的一部分。

可执行文件的每个部分都有一个固定的偏移地址,而.data部分也不例外。

但值得注意的是,可执行文件内部的偏移是固定的。 在操作系统中可能会有所不同(所有的随机地址),但这是一个操作系统的工作,为你抽象这种东西(在这种情况下创建可执行文件的虚拟地址空间)。 所以它看起来像静态变量实际上是静态的,但只在可执行文件的内存空间内。 RAM上的东西可能在任何地方。

最后,很难尝试向您解释这一点,因为您必须了解可执行文件的工作方式。 一个好的开始是搜索关于低级编程的一些解释,例如堆栈框架,调用约定,汇编语言本身以及编译器如何使用一些众所周知的技术来管理函数(通常作用域),全局/静态/本地/常量变量,以及内存系统(部分,堆栈等),以及对PE(甚至ELF)文件的一些研究。

据我了解,声明为static的变量在程序数据中有一个永久的偏移量。 这意味着当程序加载到RAM中时,变量的偏移量将始终相同。 因为程序的开始地址是全局的,所以如前所述,找到一个基于偏移量的静态变量应该是一件小事。 因此,尽管指向静态变量的指针在事物的方案中可能是随机的,但是,无论程序何时启动,其对程序存储器开始的偏移都应保持相同。 所以Cheat Engine(虽然我不知道软件)很可能存储了静态变量的偏移量,然后当软件启动时,应用这个逻辑来找到这个变量。

至于如何可以告诉它是一个静态变量…这是部分的猜测,但是当你在C中声明一个变量static的时候,我假设编译器/链接器放置了一些标志,所以操作系统知道这是一个静态变量。 也可能是所有的静态变量都以某种方式存储,或者以特定的地址偏移量存储在为某个目标系统编译的所有程序中。 再次,不太确定,但从我对内存管理的理解来看,这似乎是最有意义的。 有了这些假设,程序完全可以包含静态变量。 不同之处在于,内存是在程序运行时静态分配的,与动态相反(就像调用malloc()或类似的)。 如果变量是动态存储的,我相信有一种方法可以很容易地找到它们,所以我认为对于Cheat Engine而言,不管变量是否是静态的都不重要。 然而,正如我所假设的,Cheat引擎想要在启动时修改游戏(就像旧的GameSharks用来……啊,错过那些日子),修改静态变量可能更可靠,而不是试图找到指针和反汇编代码等。

如果你有兴趣学习更多,我建议在OSDev上检查一下这个教程 。