用 Cheat Engine 给赛博朋克 2077 写个简单注入外挂
在本文中我将展示如何用 Cheat Engine 给 Cyberpunk 2077 写一个非常简单用注入的方法实现的的无限子弹外挂。

在本文中我将展示如何用 Cheat Engine 给 Cyberpunk 2077 写一个非常简单用注入的方法实现的的无限子弹外挂。该教程的目的仅仅是为了演示如何制作一个 Cheat Engine 注入脚本,而为了达到无限子弹的效果很可能有更便捷更稳定的方式,例如寻找基址,不过该话题不在本教程讨论范围之内。

当然,请仅在本地游戏中学习实验这些技术,不要将该技术用于破坏多人游戏的平衡上。Hack ethically and responsibly.

我还是第一次写类似的教程,在逆向工程方面的经验也尚浅。如有错误,还恳请包含并指出,感激不尽。

寻找内存地址

首先,启动游戏,并且将 Cheat Engine 附加到 Cyberpunk 2077 的游戏进程上。

Cheat Engine 附加游戏进程

然后随便掏出一把枪,可以看到目前弹匣内弹药有 30 发。

初始弹药量

接下来在 Cheat Engine 中搜索 4-byte,值为 30 的所有内存地址。使用 4-byte 是因为很多游戏内类似的整数使用的都是无符号整型的数据类型,在 x64 的系统上也就是一个 DWORD,或 32-bit (4 bytes)。因此扫描 4-byte 的数据类型最有可能找到我们想要的数字。当然,有些数据也有可能使用的是 WORD 或 FLOAT 之类的类型进行存储,这时我们就需要调整 Cheat Engine 扫描的数据类型以匹配寻找的数据类型了,否则将会找不到我们想要寻找的数据。具体都有哪些数据类型可以在 Windows 文档中查看:https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types

第一次搜索

回到游戏中,随便打几发消耗掉一些弹药使内存中的数据产生变化。

消耗后的弹药量

然后再回到 Cheat Engine 搜索值为新弹药数量的地址以筛选掉无关的数据。

第二次搜索

重复几次该过程之后,最终我们会将搜索结果缩小到数个地址,但我们仍然不知道哪个是实际储存弹药量的地址,因为在消耗弹药之后这几个地址的值均会变化。

弹药搜索结果

这时我们就可以通过简单的二分法排查实际存储弹药量的地址。选中一半的数据并且修改掉,然后回游戏内查看修改是否有效。

二分法搜索地址一

我们可以看到,当我们改动了最后四个地址的值,游戏内的弹药量也改变了(此处需开几枪刷新下弹药数量),说明我们需要找的地址在这四个地址之内。

二分法搜索地址结果一

接下来重复该过程,直到排查出我们需要的地址。

二分法搜索地址二

最后确定是以下地址保存着弹药量。双击该地址就可以将他添加到下面的目录里。

二分法搜索结果

当我们修改该地址的值,游戏内的弹药量也会随之变化。虽然我们已经有了存储弹药量的临时地址,但是该地址在重启游戏或重新加载存档后便会改变。要想做到重启游戏后外挂仍然生效,必须修改游戏代码或者寻找该数据的基址(也可能有其它方式)。本教程将只会讲述如何用注入的方法修改游戏代码来实现重启后外挂仍然生效的效果。

9999 弹药

分析汇编代码

接下来我们需要寻找程序里将新的弹药量写入该地址的指令以方便修改该逻辑。右键刚刚搜索到的地址并且选择 Find out what writes to this address

寻找向该内存地址写入的命令

Cheat Engine 会需要在游戏进程上挂一个调试器,选择允许。这里比较有意思的是,x64dbg 附加到游戏进程上之后,游戏会不停的报 access violation,IDA Pro 附加到进程上之后游戏可以正常运行,但是一下断点就同样报 access violation。Cheat Engine 不但可以正常 attach,还可以正常下断点,看来是有对抗反调试的措施。

挂载调试器窗口

然后我们再返回到游戏里,消耗掉一些子弹,让游戏向地址里写几次数据。这里原来的子弹量是 30 发,我开了 14 枪,剩下了 16 发子弹。

消耗掉一些子弹

这时候返回调试器可以看到第二行的汇编代码向该地址写了 14 次数据,正好对应了我们打出的 14 发子弹,应该就是这行代码负责将计算后的子弹数写入内存。接下来选中该行,并且打开反汇编界面。

调试器结果

反汇编窗口会将程序的机器码转为汇编代码以供阅读,这部分会需要写汇编基础才能看懂。我们可以在该窗口内看到 mov [rsi+340],r12d 的命令,意思为将 r12d 寄存器内的数据移动到 RSI 指向的地址正向偏移 340 bytes 的位置。可以看出 r12d 便是计算完毕的子弹数量,而 rsi+340 这个地址便是存放子弹数量的地址。

反汇编窗口

再向上找,我们可以找到这条减法操作,子弹数量的减少就是由该条命令计算的。现在我们可以制作一个简单注入,让该减法变成加法,子弹就会越打越多。

减法操作

制作注入脚本

首先,选中要修改的行,然后从工具菜单里打开 Auto Assemble 界面。

打开 Auto Assemble

我们要制作的是一个 full injection,所以可以直接使用 Cheat Engine 提供的 full injection 模板。至于 full injection 和 AOB injection 具体都是些什么以及有什么区别,Google 讲的肯定比我好。

full injection 模板

程序会让您选择需要注入的地址,并且会自动填入刚刚在反汇编界面选中的地址,这里直接点击确定即可。

full injection 地址

自动导入的 full injection 模板如下。本教程将不会详细讲述各个部分的具体含义,有需要的话可以自行查询 Cheat Engine 的官方文档。我们在 code 代码段可以找到程序中我们需要修改的 sub cx,di 命令,接下来修改该行即可。

自动导入的 full injection 模板

我们将减法的 sub 改为加法的 add 以反转子弹数量的计算,然后就可以在菜单中用 Assign to current cheat table 将该脚本添加到主窗口的目录里。当然,除了反转子弹的计数,还可以将该行改成 NOP 锁死子弹数量等,您可以自由发挥。

修改过后的 full injection 模板

添加完毕之后,在主窗口便可以找到名为 Auto Assemble script 的脚本。启用该脚本之后,原来的减法指令会变成跳转。这里的原理是,Cheat Engine 会 allocate 一块未使用的内存地址并且将改动后的代码写入到该地址中,然后将原程序中要修改的部分跳转到新的代码处,执行完毕之后再跳转回程序原来的位置。

启动脚本

至此,一个简单的无限子弹外挂就制作完毕了。激活脚本后再返回游戏中就可以发现子弹的确越打越多了。您可以将该脚本重命名并且保存为一个 cheat table,在下次启动游戏的时候加载 cheat table 并启动脚本便可开启该外挂。

展示

进一步分析

您也可以在 IDA Pro 等软件里进一步分析游戏的代码,毕竟 Cheat Engine 的反汇编看起来的确没有 IDA Pro 的流程图容易,也没有反编译功能。

首先,在反汇编界面里复制命令的地址。

复制汇编地址

然后,在 IDA Pro 中选择 rebase program 来查看 IDA Pro 目前使用的 image base。

rebase program

随后,将 Cheat Engine 里的 offset 和 IDA Pro 里的 image base 相加,便可得到该命令在 IDA Pro 中的地址。

计算地址

最后跳转到该地址,便可以开始分析了。

IDA Pro 跳转


最后修改于 2020-12-27