对疯狂的萝卜游戏的逆向分析(part1) - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

对疯狂的萝卜游戏的逆向分析(part1)

h1apwn 技术 2020-02-05 11:20:00
430618
收藏

导语:这是此系列文章的第1部分,在该系列中我逆向了一个名为Looney Tunes:Carrot Crazy的Game Boy Color游戏。

0x01  游戏介绍

这是此系列文章的第1部分,在该系列中我逆向了一个名为Looney Tunes:Carrot Crazy的Game Boy Color游戏。这是一个相当晦涩的游戏,但是当我还是孩子的时候我很喜欢它。对于本系列的每个部分,我将设定一个目标并记录实现该目标所采取的步骤。一个目标示例可能是使“ Bugs Bunny”跳高变成原来的两倍。在我的许多工作中,我都使用BGB Game Boy模拟器,因为它具有强大的调试器和内存查看器。

Carrot Crazy是一个简单的平台游戏。玩家控制Bugs Bunny和Lola Bunny收集胡萝卜和其他东西。每个级别中的前两个阶段是相似的,但是第三个阶段是BOSS在追逐玩家的游戏。

GitHub链接:https : //github.com/huderlem/carrotcrazy

0x02  逆向方法

可以查找所有级别跳过key,然后创建自己的自定义key。

疯狂的胡萝卜游戏没有使用电池的RAM,所以当游戏断电它不保存任何数据。但是,在游戏中的某些时候会为玩家提供密码,从而使玩家可以从不同的级别开始。我们可以在不玩游戏的情况下拿到所有的密码!

密码输入画面

为了找到游戏中所有密码的列表,我们需要找到将输入的密码与一些有效密码列表进行比较的例程。首先,我们将找到密码输入的位置,这很有可能是3个相邻字节。找到密码输入的RAM地址后,可以在BGB中设置一个内存访问断点,以在读取该RAM地址时暂停执行。希望这在播放器提交密码时触发,因为某些代码需要将密码输入与一组公认的密码进行比较。

0x03  查找密码输入的RAM位置

现在还对游戏内存布局一无所知,但是我对Game Boy游戏的运作方式非常了解。RAM位于地址范围内$c000- $dfff。我希望在该地址范围内的某个地方找到这三个密码字节。可以用来找到它们的一种策略是打开BGB调试器并查看内存查看器的RAM地址。

BGB 调试器

有很多数据,如何知道要寻找什么?BGB的内存查看器是实时更新的,因此应该能够通过玩游戏来修改密码输入,并在内存查看器中看到相应的字节更改,这通常是在RAM中定位数据的非常有效的方法。Game Boy RAM并不大,所以向下滚动直到发现一个字节,该字节根据我在玩游戏时更改的密码输入而更改。幸运的是,在密码输入屏幕上,游戏中发生的变化并不多,因此大部分RAM是静态的。

当我向下滚动时,我注意到整个RAM bank 0($c000- $cfff)是静态的,并且包含游戏中使用的许多ASCII文本。我会把这些信息藏起来供以后使用。然后,我注意到开始$db00快速变化的RAM块。使用相同的技巧,我得出结论,这里是声音引擎的一部分。这是因为我可以看到某些字节正在与当前背景音乐同步变化。

最后,我看到地址处的大量RAM $df00似乎与游戏中闪烁的密码角色的头部变化的频率相同。基于空间局部性原则,三个密码字节在附近。果然,我看到位于$dee8,$dee9和$deea三个字节。通过密码输入,这些值如下:

 0 = Marvin the Martian
 1 = Daffy Duck
 2 = Yosemite Sam
 3 = Tasmanian Devil
 4 = Elmer Fudd

现在知道了密码输入存储在RAM中的位置,应该能够在ROM中找到负责将密码输入与一组已知密码进行比较的例程。

0x04  查找密码比较例程

密码输入字节必须由游戏代码中的至少两个逻辑使用。

1.检查输入的密码是否有效。

2.显示字符表示当前输入的密码。

如前所述,我将在密码输入RAM位置上添加一个内存访问断点。将在读取断点处添加到$dee8,因为这是第一个密码字符。

打一个内存访问断点

现在已经打下了断点,观察到在每一帧中会两次读取RAM地址,这使使用断点变得更加困难。访问该字节的两个例程负责清理密码字节并加载字符。这些都不是要查找的内容,因为在寻找提交密码后执行的代码。BGB在调试器中内置了一个handle,提交密码后,ROM地址上的新例程0:0736将触发断点。

在BGB调试器中,看到了断点周围例程的代码:

     ld a, 5
     ld [MBC5RomBank], a
     ld hl, $6e8c
     ld a, [hli]
     ld d, a
 .checkPassword
     ld e, 3
     ld bc, wPasswordCharacters ; $dee8
 .loop
     ld a, [bc] ; <--This is where my breakpoint triggered.
     inc c
     cp [hl]
     jr nz, .noMatch
     inc hl
     dec e
     jr nz, .loop
     ld a, [hli]
     cp a, $ff
     ...
 .noMatch
     inc e
     inc e
     ld c, e
     ld b, 0
     add hl, bc
     dec d
     jr nz, .checkPassword

这是一个非常简单的例程,它遍历一个密码表,然后将玩家输入的密码与它们进行比较。首先,此例程加载密码表。该表位于ROM bank 5的地址中6e8c,如果不是就写为5:6e8c。我们可以看到该寄存器d保存了表中的密码总数。它是密码表中位于5:6e8c的第一个字节。根据之后的.noMatch代码,还可以看到密码表中的每个条目都是5个字节长。密码字符是三个字节,另外两个是一些元数据,描述了密码的级别。

0x05  记录密码表

在十六进制编辑器中打开ROM文件,然后到ROM地址5:6e8c查看密码表的内容。

密码表

如下所示:

 Passwords: ; $16e8c
     db 6 ; number of passwords
 Password0:
     db $0, $1, $4 ; characters
     db $7, $0     ; stage metadata
 Password1:
     db $1, $4, $3
     db $15, $0
 Password2:
     db $3, $2, $0
     db $15, $ff
 Password3:
     db $2, $4, $1
     db $30, $0
 Password4:
     db $0, $2, $3
     db $30, $ff
 Password5:
     db $3, $4, $1
     db $ff, $ff

根据此密码表,游戏有六个唯一密码。问题是我们不知道元数据确切代表什么,从游戏经验中,我碰巧知道在简单和困难模式下,关卡有不同的密码。因此,可以推断出阶段元数据的第二个字节$0可能适用于简易模式和$ff硬模式。这意味着第一个字节很可能是级别ID。通过更改值并查看游戏过程中发生的情况来进行测试。

使用十六进制编辑器,我将第一个密码修改为以下内容:

 Password0:
     db $0, $0, $0 ; All Marvin the Martian
     db $2, $0     ; stage metadata

在尝试了第一个字节之后,游戏开始运行,其中不同的“名字”具有全局ID。以下是一些ID的列表:

 0: Infogrames Copyright Screen
 1: Warner Bros. Copyright Screen
 2: Language Selection Screen
 3: Title Screen
 4: Options Screen
 5: Bugs & Lola Intro Scene
 6: Studio Hallway (Hub World)
 7: Treasure Island Scene 1 Intro
 8: Treasure Island Scene 1 - Area 1

可以肯定的是,表中的第一个密码具有$7其ID的值,它对应于上面列表中的“金银岛场景1”。如果测试密码$0, $1, $4(Marvin,Daffy Duck和Elmer Fudd),则应立即将玩家带到金银岛场景1。

金银岛密码

剩下的唯一事情就是最后一个密码的行为。它具有$ff, $ff元数据的值,并且$ff似乎与ID不对应。从外部文档中,我碰巧知道开发人员留下了调试密码,该密码允许玩家在玩游戏时按START + SELECT跳过当前阶段。确实是这个密码。

总而言之,我们发现游戏可以识别所有的密码:

 Marvin the Martian, Daffy Duck, Elmer Fudd
 Treasure Island Scene 1
 Easy Mode
 Daffy Duck, Elmer Fudd, Tasmanian Devil
 Crazy Town Scene 1
 Easy Mode
 Tasmanian Devil, Yosemite Sam, Marvin the Martian
 Crazy Town Scene 1
 Hard Mode
 Yosemite Sam, Elmer Fudd, Daffy Duck
 The Space Station Scene 1
 Easy Mode
 Marvin the Martian, Yosemite Sam, Tasmanian Devil
 The Space Station Scene 1
 Hard Mode
 Tasmanian Devil, Elmer Fudd, Daffy Duck
 Ability to skip levels by pressing START + SELECT during gameplay

0x06  创建自己的密码

现在,已经对密码系统进行了完全逆向,应该能够创建自己的密码而不会破坏任何现有密码。我想要一个密码,直接到游戏的最后一步Elmer Fudd的森林。

首先,由于我要附加密码表,因此需要将密码表移至ROM中的其他位置。无法在其当前ROM位置附加它,因为我不想覆盖紧随其后的现有数据。在十六进制编辑器中,可以看到ROM bank 5的末尾有足够的可用空间,因此将现有的密码表移至该位置。

重新定位密码表

首先,必须将第一个字节更改为7,因为表中现在有七个密码。然后,将5字节的密码结构附加到表末尾。

 Password6:
     db $4, $4, $4 ; All Elmer Fudd
     db $3d, $00   ; Elmer Fudd's Forest Scene 1, Easy Mode

现在,在ROM中有了新的密码表,必须更新加载密码表的例程,因为它仍在使用旧地址。将密码表移至address $17dd6,因此将例程的开头修改为以下内容:

 ld a, 5 ; The table is still located in ROM bank 5
 ld [MBC5RomBank], a
 ld hl, $7dd6 ; New password table address

测试一下我们的密码是否有效。

自定义Elmer Fudd密码

0x07  学习总结

这是本系列逆向游戏的第1部分,我们能够对密码系统进行逆向,甚至可以将自己的自定义密码注入游戏中。在以后的文章中,我们将更深入地探讨自定义关卡等问题。

本文翻译自:https://www.huderlem.com/blog/posts/carrot-crazy-1/如若转载,请注明原文地址
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2024 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务