街机模拟游戏逆向工程(HACKROM)教程:[4]MAME的作弊功能

发布时间:2024年01月16日

需要对游戏进行逆向分析,我们首先需要了解游戏的内存系统。在一个游戏的运行过程中,游戏中所有的变动,比如玩家的血量,敌人的血量,玩家所在位置,场景的位置,剩余时间,等等一切,都在内存中有所体现。所有的数据,都保存在内存的某个地址。

比如一个玩家血量减少的大概逻辑为:

1、当被敌人攻击,程序分析敌人的攻击力数据。

2、从玩家血量的内存地址读取玩家的当前血量,把当前血量以敌人的攻击力大小减少相对应的值,再把已减少的值写入玩家血量的内存地址。

3、玩家的血量是否为空,如果为空,进入死亡程序分支。如果不为空,进入非死亡程序分支。

在这个逻辑下,我们首先需要知道玩家的血量的内存地址。我们如何找到玩家血量的内存地址呢,MAME内自带内存搜索指令,可以方便地搜索内存数据,下面,我们尝试用MAME自带的指令来搜索到"恐龙新世纪"游戏中1号机位对应玩家的血量。

我们搜索一个内存数据的逻辑为,我们首先在一定的情况下,把内存的所有数据保存下来,比如我们当前需要搜索玩家血量:

1、我们在玩家血量为满的情况下,把所有内存的数据保存下来。

2、我们再次进入游戏,利用敌人或其它方式让玩家的血量发生变化,再次搜索之前保存下来的数据,因为血量已经发生了变化,相对于之前的数据,血量的内存数据也必定发生了变化,我们把之前的数据与已变化的数据进行对比,筛选出已经发生变化的数据。

3、因为内存里的数据量通常比较大,虽然血量发生了变化,但可能有无数的数据也同样发生了变化,所以,我们通过不断地让血量发生变化,通过多次的筛选,来一步步地减少所筛选出来地址数量,直到找到对应玩家血量的地址。

我们介绍一下MAME内存搜索功能指令:

cheatinit(ci)            -初始化搜索选定的内存区域

cheatinit [[<sign>[<width>[<swap>]]],[<address>,<length>[,<space>]]]

参数1 
<sign> 可以是 u(表示无符号)或 s(表示有符号),
<width> 可以是 b(表示 8 位(字节))、w(表示 16 位(字))、d(表示 32 位(双字))或 q对于 64 位(四字); 
<swap> 可以是 s 来表示相反的字节顺序。  如果第一个参数被省略或为空,则使用上一次作弊搜索的数据格式,如果这是第一次作弊搜索,则使用无符号 8 位格式。

参数2
<address> 指定开始搜索的地址,
<length> 指定要搜索的内存量。  如果指定,将搜索 <address> 到 <address>+<length>-1(含)范围内的可写 RAM;  否则,将搜索地址空间中所有可写的RAM。
cheatrange(cr)        -添加选定的内存区域进行作弊搜索

cheatrange <address>,<length>

参数:
<address> 指定开始搜索的地址,
<length> 指定要搜索的内存量。  <地址> 到 <地址>+<长度>-1(含)范围内的可写 RAM 将添加到要搜索的区域。
cheatnext (cn)         -通过与之前的值进行比较来筛选对应的地址
cheatnextf(cn)         -通过与初始化的值进行比较来筛选对应的地址

cheatnext <condition>[,<comparisonvalue>]
cheatnextf <condition>[,<comparisonvalue>]

参数1:
all                                 更新最后的值
equal (eq)                          如果没有 <comparisonvalue>,则搜索与之前搜索相同的值;  使用 <comparisonvalue>,搜索等于 <comparisonvalue> 的值。
notequal (ne)                       如果没有<comparisonvalue>,则搜索不等于之前搜索的值;  使用 <comparisonvalue>,搜索不等于 <comparisonvalue> 的值。
decrease (de, -)                    如果没有<comparisonvalue>,则搜索自上次搜索以来减少的值;  使用 <comparisonvalue>,搜索自上次搜索以来减少了 <comparisonvalue> 的值。
increase (in, +)                    如果没有<comparisonvalue>,则搜索自上次搜索以来增加的值;  使用 <comparisonvalue>,搜索自上次搜索以来增加了 <comparisonvalue> 的值。
decreaseorequal (deeq)              搜索自上次搜索以来已减少或未更改的值(不使用 <comparisonvalue>)。
increaseorequal (ineq)              搜索自上次搜索后增加或不变的值(不使用 <comparisonvalue>)。
smallerof (lt, <)                   搜索小于 <comparisonvalue> 的值(<comparisonvalue> 是必需的)。
greaterof (gt, >)                   搜索大于 <comparisonvalue> 的值(<comparisonvalue> 是必需的)。
changedby (ch, ~)                   搜索自上次搜索以来已按 <comparisonvalue> 更改的值(<comparisonvalue> 是必需的)。

cheatlist(cl)            -显示已搜索相匹配的列表,或将它们保存到文件中

cheatlist [<filename>]


?

cheatundo(cu)         -撤消最后一次作弊搜索(仅限状态)

cheatundo

我们进入游戏来实际测试一下:

首先,我们进入游戏,最好的方式是保持满血,场景内保留一个敌人,场景内保留一个回血的道具,在"恐龙新世纪"中,比较好的地方为第一个场景进入门后会有一个回血道具,我们清理完场景,保留一个敌人和一个回血道具,在此时,我们保留一个存档:

此时,我们按键盘的"~"键进入DEBUG调试器,在命令框中输入:

ci

按F12回到游戏,让玩家的血量发生变化(被敌人攻击,或使用扣血技能,或拾取回血道具),发生了变化后,按"~"再次进入DEBUG调试器,在命令框中输入:

cn -

//如果血量减少时使用减号"-"参数;
//如果血量增加使用加号"+"参数;
//如果血量不变使用"eq"参数;

这里提示,对比筛选出59个对应的地址。

再次按F12回到游戏,让玩家的血量发生变化(被敌人攻击,或使用扣血技能,或拾取回血道具),发生了变化后,按"~"再次进入DEBUG调试器,在命令框中输入:

cn -

//如果血量减少时使用减号"-"参数;
//如果血量增加使用加号"+"参数;
//如果血量不变使用"eq"参数;

尽量多次循环以上步骤,直到得到的地址足够少,最好可以得到唯一地址。

如果未能得到唯一地址,可以使用命令:

cl

列出已经得到的地址列表,尝试一个个测试得到的地址。

我们现在得到了唯一的地址:FFB2E1

我们在调试器中,新建一个内存窗口:

输入我们得到的地址:

在68000中,我们最好使用偶数地址,比如FFB2E1,我们选择偶数地址:FFB2E0

?

我们可以看到,当前FFB2E1地址的值为3D,这是一个16进制值。也就是说,当前玩家的血量对应的值为3D,我们可以尝试在内存窗口把该值进得更改,鼠标选中该值,在键盘输入你想需要的值,如50:

回到游戏,我们会发现,血条并未发生变化,因为血量发生变化后,游戏的显示并未发生变化,这其中的逻辑为,当血量发生变化后,会调用血条显示的程序。但这时通过其它方法去更改玩家的血量时,程序并不会进入血条显示的程序。所以,在显示上,血条并未发生变化。我们尝试再次在游戏中让血量发生变化(被敌人攻击,或使用扣血技能,或拾取回血道具),才可以测试出,我们对血量的改动是否成功。

以上就是对于MAME搜索内存的介绍,几乎所有逆向工程的开始都基于对于内存的搜索,所以,在之后对于游戏的所有逆向研究,几乎都会用到内存搜索功能。建议对该功能更加详尽地了解。

文章来源:https://blog.csdn.net/m0_50114967/article/details/135431651
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。