坦克大战,一款经典的FC游戏,相信很多小伙伴们绝对玩过这款游戏,场景丰富,道具众多,支持自定义地图,基地老巢的设计使得游戏过程更加紧张刺激,单人游戏难度较大,双人游戏更需要配合,一不小心队友还会把自家老巢给击毁,这样的猪队友不要太多哦。

今天我们来做一个内存修改游戏玩家生命数值的演示,原理其实很简单:每个玩家的生命值必然是存储在一个变量里的,对于CPU为8byte,内存资源极其限制的FC系统,可以推测,这个变量大小占用应该是 1 byte,可以支持0-255的生命数,所以只要找到这个变量的地址,然后使用工具修改即可实现。

我使用的添加了DEBUG功能的VirtuaNES模拟器,可以对显示系统、CPU、内存、进行实时观察调试,比较方便。也可以使用其他模拟器实现调试,曾经在linux平台下使用gdb attach运行liteNES,加载游戏rom之后进行单步调试,同样可以做到内存修改。顺便说一句,liteNES是一个开源的FC模拟器,代码写的很精简,实现了CPU和PPU的模拟,对NES模拟器原理有兴趣的朋友可以研究一下其源代码,比较有意思。

  1. 打开模拟器

2. 打开所有调试窗口,依次点击RAM、VRAM、图案表、背景、精灵。这些是NES系统里面的重要组件,各个组件的具体作用请见文末。

3. 设置控制器手柄,由于之前我已经设置过了,所以这里直接点击确认即可。

4. 上一步已经在控制器中配置好了各个按钮,输入相应的按钮进入选择界面开始游戏

5. 修改内存地址0x51处的1 byte,这里存着1P的生命数!我是怎么知道是这个地址,请看最后的说明,鼠标点选memory窗口中的数值之后,直接输入键盘数字键即可修改,可以看到我从原来的0x3修改成了0x66,观察游戏窗口处的1P生命数,变成了G1,这是因为0x66的十进制是102,而显示的生命数只支持两位数的缘故。

6. 修改成99命,实际上右侧显示的是剩余的生命,加上当前游戏的生命,总共是100命,故生命数变量需要改成100,done!


Q1 调试界面中各个组件的含义是什么?

A1:

Q2 如何得知1P生命数变量地址在0x51处?

A2:NES系统的CPU为6502,6502有一种特殊的寻址方式称之为零页寻址,这种寻址方式可以不在指令中指定物理地址,而使用默认的一块内存进行寻址,所谓的零页,即CPU内存地址0x0-0x100。使用零页寻址可以降低代码空间,提高取值执行效率,通常存在零页的数据是系统级别的数据,需要在代码中频繁访问,或者说,全局变量。首先初步推断生命数存储在零页之中,而后,使用模拟器开始游戏,此时故意令1P损失一条生命,此时存储生命数的变量必然会减1,对比损失前后的零页内存,观测 内存变化 n -> n-1,即可获得1P生命数变量的内存地址,零页内存只有256字节,所以直接肉眼观测即可较容易得出目标地址。

视频教程:自己动手破解FC游戏