decimal - 解构神奇宝贝故障?

标签 decimal hex reverse-engineering

(如果这是错误的地方,我很抱歉。我认为这肯定与编程相关,但如果这属于其他网站,请告诉我)

我从小就玩神奇宝贝红和蓝,这些游戏非常有趣,但因存在许多可利用的故障而臭名昭著(例如,请参阅 this ridiculous speedrun of the game,它使用内存损坏将项目屏幕变成十六进制编辑器)。

最近,我发现了游戏中一个有趣的速通游戏,它使用了一个名为“ZZAZZ 故障”的故障来破坏重要的内存位置,并让玩家几乎立即赢得游戏。根据 the author's description of the speedrun ,ZZAZZ 故障的工作原理如下:

To start a Trainer battle, the game needs to load a lot of data, such as [...] the money he'll concede if defeated. When it loads the money is where things can get really ugly. For reasons that are beyond me, money is stored in a completely different manner, the game uses a data structure of three bytes and instead of converting the value to binary, it stores it in "human" representation. For example, $123456 would be stored as 0x123456 instead of 0x01E240, the proper conversion.

[Some invalid entries in the Trainer table] point to location with invalid money data. When the game tries to perform arithmetic with these data in said structure, it goes nuts and starts overwriting huge portions of RAM. More specifically, for every block of three bytes, two of them will contain 0x9999 (the maximum amount of money a trainer could give). This pattern repeats itself many times through RAM. To see this better, I recommend pausing the video on the emulator after the ZZAZZ trainer is faced and set VBA's memory viewer to 0xD070.

这种分析是有道理的,但作为一名程序员,我忍不住想知道程序员到底是如何编写使这成为可能的代码的。如果输入不是有效的十六进制编码的十进制数,我能想到的编写将十六进制编码的十进制数转换为十进制数的函数的方法都不会开始用 0x9999 填充随机内存块。

我的问题是 - 如果没有专门设计以这种方式失败的算法,是否有一种从十六进制编码的十进制到十进制的转换的直接实现,当输入无效值时可能会导致这种内存损坏?

再次,如果这是题外话,我深表歉意。我的想法是,这个网站上的其他程序员可能也是玩这个游戏长大的,这听起来像是逆向工程中的一个有趣的练习,试图找出这样的故障是如何可能发生的。

最佳答案

老实说,我的猜测是,这只是某人在目标上编写第一款游戏时出现的一个愚蠢而令人讨厌的故障。 《口袋妖怪红/蓝》是该系列中的第一个,并且有很多其他故障,任天堂通常会排除批处理测试,我想知道它是如何通过的。滚动屏幕移动问题是让我困扰的一个问题。无论如何,谁知道他们在想什么。也许这个区域是通过脚本写入的,因此存储的内容不同。也许位模式 0x0101 用于显示内存已释放,并且该代码意外地在奇怪的地方变得疯狂。我可以翻阅 Z80 代码并在该平台上重温我自己的游戏开发时间,但是呃。尝试解密他们的想法需要太多工作。

不过确实赚了很多钱......

编辑1:

好吧,你已经赏金了。我花了更多的时间仔细记忆,为你找到了一个花絮。 GBC/DMG 有一个称为DAA 的操作码。小数调整累加器 (A)。其作用是将累加器中的值转换为 BCD 格式。您看到的内存区域已经采用 BCD 格式:http://en.wikipedia.org/wiki/Binary-coded_decimal

现在我可以告诉你,在我手工编写游戏 Z80 汇编程序的 4 年左右的时间里,我从来没有需要过这个操作码,只在我们制作的棒球游戏中看到它使用过一次,用于显示一些内容分数。虽然它是 1 周期算术指令,但我在正常编码中从未真正找到它的良好用途。唔。实际上我还保留着任天堂的 DMG 技术文档。想想吧;)无论如何,除了它以时髦的方式与许多标志混淆之外,它也没有什么令人兴奋的。

我的猜测是该表被假定为 BCD 格式。将其更改为该格式之外的内容会导致内部数学变得极其困惑 - 在不应该设置的情况下设置进位和零标志。这会导致从一列溢出到下一列,从而导致计算非常大的数字。如果不直接查看读取该区域的相关操作码,我不能肯定地说,但我猜测这里有一个包罗万象的检查,表明在 BCD 完成后是否仍设置进位> 数学,设置最大值而不是存储负值或越界值。该指令或 DAA 指令在接收垃圾数据时返回 0x99 作为其返回值,尽管我对此不太确定。

希望这有帮助...

关于decimal - 解构神奇宝贝故障?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6876642/

相关文章:

string - 读取文本文件时将十六进制转换为整数

java - 使用 java 代码将 RGB 转换为 Hex - Android

ios - 是否可以通过逆向工程从 .ipa 文件中获取原始源代码?

sql - 将十进制数转换为 INT SQL

highcharts - 删除 Y 轴上的小数位,只有一个点

python - 将科学记数法转换为 float

java - Hibernate重复类名异常

c# - 如何在 C# 中为 "decimal to binary"修复此代码

c++ - 将奇怪的十六进制电话号码转换为普通数字

compiler-construction - 如何对编译器进行逆向工程?