如何逆向NDS游戏(上):配置环境
本教程将使用任天堂DS游戏《宝可梦不可思议的迷宫:空之探险队》演示介绍逆向游戏的通用流程,本文所使用的技巧也可用于其他游戏。
关于本教程
本教程将手把手教你:
- 配置逆向工程环境。
- 入门汇编语言。
- 使用逆向工具Ghidra分析汇编代码。
- 使用DesmuME模拟器的调试工具:检查游戏内存/运行时调试。
- 寻找游戏资源和数据的逆向工程策略。
本教程讨论了一些特定于NDS游戏的逆向工程技巧。如果你需要更通用的逆向工程教程,我(译注:原作者)推荐你去看GBA版教程。
跟随本教程需要什么技能?
- 编程知识(最好有C或C++),加上下列相关方面:
- 指针
- 结构体
- 位运算
- 16进制数字
- 能使用模拟器基本顺畅地运行游戏。
- 对游戏逆向感兴趣!
什么是逆向工程
在编程语境里,逆向工程是指在不访问程序的原始实现(即源代码、文档等)的情况下弄清楚程序如何工作的过程。大多数游戏不会公开发布源代码,但可以通过分析游戏文件中的二进制数据来了解和重建游戏的许多细节。
对游戏进行逆向工程有几个原因:
游戏知识
游戏隐藏了许多有关其机制和实现的细节,游戏中的经验实验只能让你走这么远。进入逆向工程,你可以分析游戏的代码并准确了解游戏的工作原理。有了足够的游戏知识,人们可以运用这些知识来构建有用的工具,例如宝可梦战斗伤害计算器,乃至战斗模拟器。

打Mod / 破解
在没有内置关卡编辑器的情况下,如何在游戏中构建自定义关卡、创建可让你无限飞行的作弊代码或为角色提供自定义的搞笑武器?大多数情况下,人们会对游戏进行逆向工程,最终搞明白如何修改游戏代码以添加这些功能。作弊代码(即GameShark和Action Replay等设备的作弊代码)也需要逆向工程来创建;作弊代码只是一组用于作弊设备的加密指令,为了修改内存或将少量代码注入游戏。
利用游戏漏洞
有一类漏洞被称为任意代码执行 (Arbitrary Code Execution, ACE),它允许玩家将代码注入游戏,以执行硬件支持的几乎所有操作。包括无限物品、立即跳转到片尾字幕,甚至将SNES变成Skype视频聊天。 ACE需要对游戏代码有详细的了解才能充分利用,而逆向工程在设计这些漏洞方面起着重要作用。

解包获得情报
在内容定期更新的游戏中,开发人员有时会在游戏正式发布之前将新的游戏资源添加到游戏中。早期发布的演示版本还可能隐藏着完整游戏的部分内容。对游戏进行逆向工程以提取这些资源,并在正式发布之前了解新内容。
配置逆向工程环境
需要首先准备好以下软件:
- Ghidra - 用于静态代码分析的逆向工程工具。
- DeSmuME - 具有调试和内存查看功能的NDS模拟器。
- 《宝可梦不可思议的迷宫:空之探险队》的ROM - 我们将要逆向工程的游戏。请确保使用游戏的USA/NTSC版本;其他版本如EU/PAL版本数据和功能的位置不同。
本教程使用DeSmuME作为首选的NDS模拟器,但值得一提的是另一个常用于调试的NDS模拟器[No\(GBA](https://www.nogba.com/)。No\)GBA具有比DeSmuME更高级的调试功能,但稳定性较差且用户不友好。
只有Windows版本的DeSmuME具有适当的逆向工程调试功能。不幸的是,对于macOS/Linux用户来说,在这些操作系统上调试NDS游戏的唯一选择是DeSmuME部分功能的gdb stub,即使你熟悉gdb,它也无法很好地工作。Ghidra与所有操作系统兼容,因此如果你愿意,你可以选择在macOS/Linux上使用Ghidra并在Windows上使用DeSmuME。或者,你可以按照本教程的GBA版进行操作,因为有运行在macOS/Linux上且支持调试的GBA模拟器。
以下Ghidra配置教程改编自UsernameFodder的出色指南,出自pmdsky-debug项目。
解压ROM
要开始分析NDS的ROM,首先需要解压以提取游戏代码的二进制文件。要解压ROM,可以使用DSLazy(Windows)或ndstool(macOS/Linux)。
使用DSLazy
- 下载DSLazy并解压zip文件。
- 运行DSLazy的可执行文件(
dslazy.exe),启动程序。

- 单击DSLazy窗口左上角的
…,然后在文件系统中选择《空之探险队》的ROM文件。 - 单击nds unpack按钮解压ROM。这需要几秒钟才能完成。有时即使成功完成,DSLazy也无法显示解压已完成。如果解压时间超过几秒钟,请检查下一步以查看文件是否已解压。
- DSLazy将打开文件资源管理器,其中包含一个包含解压文件的文件夹。此文件夹名为“NDS_UNPACK”,位于DSLazy所在的文件夹中。
使用ndstool
- 下载ndstool(.tar.bz2文件)并打开存档。
- 打开终端并“cd”到解压的“ndstool-2.1.2”文件夹,然后运行“./configure && make && make install”。
- 根据你的权限,你可能需要运行“sudo make install”而不是“make install”以使用管理员权限运行安装。
- 创建一个文件夹来存储解压后的 ROM 文件,然后“cd”到该文件夹。
- 运行
ndstool -9 arm9.bin -7 arm7.bin -y9 y9.bin -y7 y7.bin -d data -y overlay -t banner.bin -h header.bin -x <ROM path>,其中<ROM path>是文件系统上《空之探险队》的ROM的文件路径。ROM将被解压到你创建的文件夹中。
设置Ghidra

Ghidra是美国国家安全局(National Security Agency, NSA)开发的一款免费开源的逆向工程工具。Ghidra可以分析游戏ROM等二进制数据、输出汇编代码、甚至反编译出C语言代码,我们可以根据这些代码对游戏进行逆向工程。这种分析是在游戏未运行的情况下进行的,所以被称为静态代码分析(相对于在游戏运行时调试的动态代码分析)。
对业余爱好者来说,Ghidra是理想的代码分析、反汇编工具,功能齐全且无需付费。Ghidra也有付费替代品,作为逆向工程行业标杆的专业商业软件IDA。不过,IDA的完整版本售价数千美元,对许多业余爱好者来说都太贵了,而IDA的免费版本又没有足够的功能满足我们的需求。
要安装Ghidra,请按照Ghidra官方网站上的说明进行操作。
如果你使用的是较新版本的macOS,则需要在设置项目之前授予Ghidra反编译器的运行权限。在Ghidra文件夹中,转到 Ghidra/Features/Decompiler/os/mac_x86_64,右键单击decompile可执行文件,选择open,并在macOS警告无法验证开发人员时确认open。
安装后启动Ghidra,将看到以下页面。

创建Ghidra项目
使用解压缩的《空之探险队》ROM文件来创建一个新项目。
- File > New Project…
- 项目默认设置为“Non-Shared Project”。点击Next。
- 选择项目名称和保存项目的目录,然后点击Finish。
- File > Import File…
- 从解压缩的ROM文件中选择arm9.bin文件。
- 为Ghidra选择一个指令集架构(Language)来分析该二进制文件。NDS使用ARMv5T(具体来说是ARMv5TE)指令集,采用小端序(ARM:LE:32:v5t),你可以通过在language选择中搜索“v5t”找到,然后选择Endian列下带有“little”的选项。

点击Options…并将基址(Base Address)设置为02000000。
点击OK让Ghidra检查该二进制文件。
完成后,Ghidra会显示一些检查细节的报告。点击OK继续。
双击Ghidra中的ROM来打开Ghidra的代码查看器。
Ghidra会提醒是否分析二进制文件。暂时点击No,因为还要做一些设置。
如果此时运行分析,也不会造成任何不良影响。Ghidra只是会根据现有信息进行部分分析,稍后可以在一切都设置好之后重新运行分析。
点击File > Add To Program,然后在解压缩的ROM文件中查找
overlays文件夹。选择该文件夹中的overlay_0029.bin。点击Options…
将块名称设置为“overlay_0029.bin”。
块名称不会影响分析,实际上可以是任何名称。不过我建议使用与overlay文件相同的名称以便于跟踪。
将基址设置为22DC240。
点击OK确认你设置的选项,点击OK添加overlay,然后当Ghidra显示添加完成时再点击OK。
你可能注意到选项中有一个Overlay复选框,但对现在来说没啥用。请保持未选中状态以避免干扰Ghidra的分析。
使用overlay文件
overlay_0010.bin重复步骤12-16。使用22BCA80作为该文件的基址。使用overlay文件
overlay_0031.bin重复步骤12-16。使用2382820作为该文件的基址。通过选择
Analysis > Auto Analyze ‘<project>’…运行分析,或使用热键 ‘a’。使用默认的分析设置并点击Analyze。
等待Ghidra分析二进制文件。这可能需要几分钟。
当Ghidra的分析完成后,验证Ghidra是否正确设置。按‘g’,输入“22E0354”,然后按OK。你应该会看到如下页面。此时,Ghidra已经设置完成,可以开始逆向工程游戏。

设置步骤解惑
如果我不告诉你,你咋知道要选ARM:LE:32:v5t?
首先,搜索NDS用的是哪款CPU(例如,维基百科),然后你就会发现NDS使用两颗CPU分别是ARM946E-S和ARM7TDMI。从NDS的技术规格可以知道,NDS的ARM9 CPU是用于游戏机制(gameplay mechanisms)的那颗CPU。知道了CPU信息,你就可以搜到CPU的指令集和架构。ARM的文档说ARM946E-S用的是ARMv5TE架构。这意味着ARMv5T就是我们要找的东西。“ARMv5TE”里的后缀“E”表示支持额外的信号处理指令,不过你不需要关心这些指令。
至于端序(endianness)(数据中每个字(word) 的字节存储顺序),大多数ARM CPU都是“双端”的:同时支持小端和大端。实际操作中,大多数ARM程序都是小端的。如果Ghidra用小端序逆向出的反汇编代码难以理解,请尝试大端,看看输出的代码是否有所改善。需要注意的是,某些CPU(例如使用PowerPC指令集的CPU(例如 Wii))主要采用大端序。
项目设置在添加overlay时会使用一些魔数(magic numbers,没有任何文档或注释的数字,但凡开发者搞不明白为什么是这个数的都叫魔法——译注)。本教程稍后将讨论overlay,包括如何自行找到这些数字。
有些游戏会压缩arm9.bin和覆盖文件,可以使用这个工具解压。在《空之探险队》中,汇编文件未经压缩,因此你无需担心解压问题。
设置DeSmuME以运行《空之探险队》
设置好Ghidra之后,你还需要设置NDS模拟器,然后过掉游戏开场动画。
- 从DeSmuME网站下载DeSmuME的最新稳定版本,并解压到心仪的文件夹中。
- 打开DeSmuME,转到File > Open ROM…,然后在文件系统中选择《空之探险队》的ROM。确保使用原始ROM(.nds)文件,而不是从中解压的文件。
- 如果需要,请在Config > Control Config查看和配置按钮映射。
- 观看游戏的介绍过场动画,然后开始新游戏。
- 游戏开始时有一个个性测验,它将决定你的玩家角色。回答问题,无论诚实与否,游戏都会为你分配一只神奇宝贝。
- 为自己、伙伴宝可梦和伙伴选择一个名字。
- 决定玩家和伙伴宝可梦后,你将进入过场动画。过场动画结束后,你将进入游戏的第一个迷宫,Beach Cave。
- 进入Beach Cave后,你就可以对游戏进行逆向工程了。

设置好Ghidra和游戏后,下一步就是打开游戏并阅读代码。你需要知道如何阅读汇编代码,下一节就将介绍。