如何在我使用 Cheat Engine 逆向的游戏中查找对象数组(实体、敌人)?

逆向工程 拆卸 ollydbg 调试 调试器 结构
2021-07-03 03:47:09

我正在使用 Cheat Engine 和 OllyDBG 反转游戏,通过读取和监控 FPS 游戏中的内存地址,这些地址将包含敌人的坐标(xyz)。

我的目标是找到一个地址或模式,让我可以遍历最多 32 个敌人以读取他们的所有坐标,为此我一直试图在他们的每个地址之间找到一个模式,但没有运气. 我已经能够收集 3 个不同的敌人地址,这些信息很有用,但是搜索 32 个地址是一项比我认为必要的工作需要更多的努力。

如前所述,我可以访问前 3 个敌人地址,如果根据该信息可以通过 Cheat Engine 或其他逆向工程软件追溯到基地,我们将不胜感激。

最终我的问题是,有没有办法从内存中的一个地址检测指针数组,例如,如果我有 3 个敌人坐标,我可以以某种方式将内存位置追溯到访问所有 32 个敌人地址的地址,无论它是否是通过使用作弊引擎或其他逆向工具。

2个回答

(OP 没有说明他是否知道结构是如何布局的。看起来他假设它们并不复杂。我将回答一个更一般的问题,通过假设结构有点复杂来避免局部性问题)

我想到了几种找到其他结构的方法:

签名扫描内存

一旦你有了一些结构的例子,也许找到其他结构实例的最简单方法就是在所有三个结构中找到匹配的常量。一些值可能是常量,表示适用于继承的更高级别类中的所有敌方实体的属性。

优点:

  • 这很容易实现,可以通过这个 Cheat Engine 来完成。
  • 在一般情况下,它应该在程序重新启动后幸存下来,每次运行游戏时都不需要找到这三个结构。

缺点:

  • 不那么健壮。版本之间的东西可能会发生变化,您认为不变的数据实际上可能会在您没有看过的某些情况下发生变化。

指针搜索

某处可能有一个指向每个实体的指针。您可以轻松地在内存中搜索您找到的结构的地址,并检测包含所有实体的数组/结构。您也可以遍历在结构本身中找到的数组,您可能正在查看链表。

优点:

  • 易于实施。
  • 会比以前的方法更健壮一些。

缺点:

  • 您仍然需要以某种方式找到第一个实体。

寻找构造函数/类构造函数

无论是像 C++ 或 ObjC 这样的面向对象语言,还是像 C 这样的过程语言,都必须有一个函数来启动结构。通常很容易找到-分配对象后调用的第一个函数,非常独特的程序集-主要是初始化代码。

如果我们谈论 OO 代码,找到虚函数表或类似的构造将使您轻松找到构造函数,遍历继承并找到至少一部分操作函数。

获得构造函数后,您可以轻松获得所有分配,并查看保存指针的位置。

优点:

  • 相当健壮
  • 更好地理解实体如何保存在内存中。

缺点:

  • 静态 RE。通常更难做(获得一个好的反汇编程序)

反转结构

这需要更多的逆向工作,但可以让您找到搜索实体的最佳方法。使用 Cheat Engine 和 IDA,手动映射结构、元素/成员、操作结构的函数。

如果涉及任何指针,请遵循它们并反转您遇到的其他结构。

优点:

  • 强大的
  • 做你想做的正确方法。真的明白是怎么回事了。促进未来的能力/功能。

缺点:

  • 更多的工作,更难做。很多RE。

笔记

至少我提到的一些方法在分析程序时找到指向所有实体的指针可能只是第一步。您可以搜索对列表本身的引用,并获得在每次程序重新启动时自动查找实体的更好方法。这消除了一些缺点。

首先找到您要查找的地址。然后循环这个:

  1. 找到基数(记录的开头)。
  2. 剖析围绕此的内存以识别数组或链表。
  3. 在内存中搜索指向该基的指针。

示例

扫描查找地址的参数30000032

找出这条记录的基础是30000000

检查内存 - 没什么特别的。

在 处找到指向基数的指针20000004

找出记录的基础是20000000

检查内存 - 仍然没有......

在 处找到指向基数的指针10000008

找出基数是10000000

检查内存 - 所有指向我要查找的对象的指针彼此相距 12 个字节。(显然这是某种集合。)

最后一次内存扫描指针以确保我在0000040.

找到指向该集合的指针,紧接着:集合中对象的计数。

重新启动游戏/计算机几次以找到指向该地址的一致指针。

用啤酒奖励自己的出色工作。

如何找到基数:我喜欢使用“指针扫描”,并检查最后一个偏移量。最常见的最小的通常是正确的。

有时,我试图在分配的内存的开头找到一条记录,在这种情况下,我确定某些内容是基本的。

另一个技巧是在内存中一个接一个地找到两个,确定它们的“最大大小”,这意味着基数不能超过内存中的这个数字。

如何识别集合:它们中的大多数都是非常有组织的,具有特定的偏移量,或者具有指向相同类型对象的指针。

就像如果你有:

Pointer to Player 1 data,
4 Bytes
4 Bytes
Pointer to Player 2 data,
4 Bytes
4 Bytes
Pointer to Player 3 data

它应该敲响警钟。

请记住,这种对齐可能会在源中随机发生,因此请尝试搜索:Player 3 数据、Player 3 数据 +/- 4、Player 3 数据 +/- 8。

无论如何,如果你发现这样的东西,你很可能真的很接近。

这对我有用,希望对你们也有用。