关于模拟器:使用Ghidra对PSX游戏进行逆向工程

3次阅读

共计 4575 个字符,预计需要花费 12 分钟才能阅读完成。

应用 Ghidra 对 PSX 游戏进行逆向工程

这是我在钻研 PlayStation(PSX)逆向工程时总结出的小手册。如果你对逆向工程的基本概念不相熟,请先看什么是反编译?

读取 PlayStation 光盘

PlayStation 光盘是以规范的 ISO 9660 CD-ROM 格局记录的,能够在 PC 上失常读取。光盘映像文件(如.ISO、.BIN/CUE)能够用 AcetoneISO 或 PowerISO 等软件进行 (虚拟光驱) 挂载或内容提取。尽管有时会有意外:

1. 有些文件可能实际上是暗藏的。大多数 PSX 游戏所应用的 PsyQ API 可能基于数值扇区地位 (LBN) 而不是文件名从磁盘中读取文件,但 PC 无奈读取。

2. 一些 PSX 光盘成心制作出坏块,作为避免复制的反盗版措施。

3. 一些读取光盘镜像的软件在解决多轨光盘时有问题。你可能要做一些奇怪的事件,比方把第一轨的.BIN 加载到 AcetoneISO 中,或者用 binmerge 合并多个.BIN,或者制作一个只包含第一轨的假.cue 文件。

不过,至多有两个要害文件通常是容易读懂的:system.cnf,它将通知你主游戏可执行文件的文件名;以及可执行文件自身,它通常被命名为 PSX.EXE 或相似 SLPM_86.053。这就是软件逆向剖析所须要的文件。

应用 Ghidra 开始剖析可执行文件

Ghidra 是美国国家安全局 (NSA) 开发的一款逆向剖析软件,于 2019 年收费颁布。尽管有其余相似的工具,如 radare2 和 IDA Pro。而 Ghidra 岂但十分弱小,又收费。

Ghidra 可能原生地解决 PSX 的指令集(MIPS R3000, Ghidra 将其了解为 MIPS 默认的 32 位小端模式)。插件 ghidra_psx_ldr 可辅助进行 PSX 专用的剖析。

下载并解压 Ghidra。下载 ghidra_psx_ldr 的最新压缩包,不解压,而将其放入 Ghidra 的文件夹中。通过在 Windows 上运行 ghidraRun.bat 或在 Linux 上运行./ghidraRun 启动 Ghidra。从菜单中选择 File – Install Extensions 并抉择 ghidra_psx_ldr。

创立一个新的 non-shared project (File – New Project)。单击列表中的我的项目入口 (project entry) 并单击绿龙图标以关上代码浏览器(Code Browser)。在这个新窗口中,点击 File – Import(或按下 I 键),并抉择你的 PlayStation 可执行文件。

软件当初应该曾经提醒您 Auto-Analyze(主动剖析)。如果临时不剖析,您能够稍后在 Analysis 菜单中运行它(或按 A 键)。Auto-Analyze 须要不少工夫。之后,按 CTRL- S 保留。以备未来的不时之需,请留神保留后会革除撤销记录。

默认关上了很多不须要的窗口。你比拟须要的窗口是 Symbol Tree(列出变量和函数名),Listing(MIPS 反汇编后果)和 Decompile(反编译为 C 语言)。其余窗口当初不过是占据空间罢了。

了解汇编指令

您当初有成千上万行 MIPS 汇编代码,可能只有很少变量和函数领有有意义的名字。如果您不相熟 MIPS 汇编,这将使人望而却步。

首先,咱们宏现的了解汇编代码。以下是一个片段:

                     **************************************************************
                     *                          FUNCTION                          *
                     **************************************************************
                     undefined myrand()
                       assume gp = 0x800f0d90
     undefined         v0:1           <RETURN>
                     myrand
800425d0 0f 80 03 3c     lui        v1,0x800f
     assume gp = <UNKNOWN>
800425d4 f0 01 63 8c     lw         v1,offset rng_800f01f0(v1)                       = ??
800425d8 0f 80 01 3c     lui        at,0x800f
800425dc 77 03 62 24     addiu      v0,v1,0x377
800425e0 08 00 e0 03     jr         ra
800425e4 f0 01 22 ac     _sw        v0,offset rng_800f01f0(at)                       = ??

这里的 “FUNCTION “ 是一个正文,代表 Ghidra 认为这是一个函数的起始地位,兴许是因为主动剖析发现有跳转指令指向这个地址。

Undefined myrand()是给出的函数名。因为可执行文件没有保留其编译前的函数名(元数据,metadata),所以简直总是应用 FUN_800425d0 这样机械化的名称。当你最终钻研出一个函数或变量的性能时,你能够点击它的名字并点击键盘上的“L”来输出新名字,其扭转将在整个程序中失效。

如果一个函数开始被事后标识,请感激 ghidra_psx_ldr 将其辨认为对 PSX devkit 中的一个 PsyQ 规范库函数的援用。这可能是了解函数性能的突破口。例如,跟踪规范 rand 函数能够应用了解游戏解决随机性的机制;print 函数可用于输入调戏信息;write 函数在 PSX 游戏中总是用于写入记忆卡(Memory Card),这是找寻游戏要害变量的突破口,它们用于存储游戏至始至终用到的信息。

每一行汇编代码的最右边都有一个 8 位 16 进制数 (例如 800425d0)。这是这个指令(机器码) 在内存中的地址。PSX 软件的内存地址通常从 0x80000000 开始存,而不是 0。但两者都指向雷同的物理内存,例如 0x800425d0 和 0x000425d0 指向雷同的内存(请浏览 Nocash PSX Specifications 网页的 Memory Map 条目以获取详细信息)。

之后是四组两位十六进制数。这是最右边的地址指向的 32 位空间中的四字节内容。内容或者是指令(机器码),或者是四字节变量,或是其它。

再之后是机器码代表的汇编指令。少数状况下,浏览 Decompile 窗口的 C 语言可能会更有用。

最初是分号键 (;) 以插入正文。反汇编窗口和反编译窗口都可插入正文。

辨别代码和数据

Ghidra 很善于辨认代码,但并不完满。因为可执行文件中所有内容都是原始字节码,所以它有时可能不能正确的辨认一段代码,或混同数据类型。

如果您猜想一大段无奈辨认的数据可能是代码,请抉择第一个字节并按 D 键以进行反汇编。有时,这实际上是一个函数,但没有从任何中央间接调用,则请点击 F 将其转换为函数。如果产生谬误(例如,产生的“代码”是不正确的),只需按 Ctrl- Z 撤销。您还能够按 C 键将已辨认的内容倒转回未辨认的字节码。

您还能够右键单击一行代码,点击 Data,并抉择要标识的数据类型。这对于辨认字符串很不便。特地是日本游戏常常应用 Shift-JIS 编码,而 Ghidra 不会自动识别。右键单击任意字符串,到数据 - 设置和设置字符集 Shift-JIS。更好的是,数据 - 默认设置将为所有字符串设置此值。更好的方法是, 在 Data – Default Settings 中设置,将会对所有字符串失效。

Ghidra 甚至容许您输出字符串的翻译。您能够参考机器翻译网站 WWWJDIC。

跟踪代码流

如果遇到函数或变量,能够双击它,或将键盘光标移到那里并按 Enter 键来拜访它。您能够通过按工具栏上的“左”键或键盘上的“Alt+ 左”键返回到之前的地位。

函数的右上角兴许有一个 XREF 列表,这是调用它的其余函数的列表。您能够抉择一个变量或函数并按 Ctrl-Shift- F 来查看调用他的代码。一种分析方法是从曾经确定性能的货色 (字符串或函数) 做为突破口,跟踪哪些函数应用它,以钻研这些函数是如何工作的。

您做的每一个标记都好像是一块拼图,以帮忙你了解其它代码。

用调试器实时监督内存

只管 ghidra_psx_ldr 有一个调试器,在我写这篇文章时,它的性能还很无限。仿真器 Mednafen 有一个更弱小的调试器,它能够让您实时察看和批改内存。

设置 Mednafen 并应用像 Mednaffe 这样的 GUI 运行它。启动一个游戏(它能够加载 BIN/CUE 文件,即使在 PC 上不能正确读取)。如果你在游戏控制器上遇到问题,请遵循以下阐明(倡议装个手柄,这样你就能够在调试器屏幕关上的状况下用键盘、鼠标输出信息):

  1. 启动游戏
  2. 按下所有控制键和方向键,把摇杆转到最大,按下所有 L / R 键
  3. 按 F3 键从新抉择控制器(翻译可能谬误,不影响了解)。
  4. 应用 Alt-Shift- 1 启动控制器配置,按批示按下按钮。

控制器只须要配置一次。

当初,按 Atl- D 加载调试器。Mednafen debugger documentation 提供应用调试器的全面信息,但最重要的是,Alt- 1 显示 CPU 信息,S 键终止或单步步过,R 键持续,Alt- 3 显示内存信息。这些视图都实时更新。

在内存信息窗口,按 G 键并输出地址以跟踪。Mednafen 显示的地址与 Ghidra 中的地址统一,只是它们以 0 而不是 8 结尾。您能够实时察看已知变量的变动。您还能够按 D 键将内存转储到文件中,以便当前剖析。从 0 转储到 200000(十六进制),大小为 2MB。

其余可执行文件(动静加载技术)

PSX 只有 2MB 的 RAM 和 1MB 的 VRAM,程序最大只能是 2MB。与 CPU 能够间接寻址 ROM 的卡带游戏机不同,基于 CD 的游戏机必须先将程序加载到 RAM 中,因而须要加载工夫。对于许多 PlayStation 游戏来说,这曾经足够了,但对于简单的游戏来说,可能还不够。

解决方案是 PsyQ 动静加载技术,其中多个程序块保留在独自的文件中,主可执行文件能够依据须要加载和卸载这些文件。例如,Tokimeki Memorial 有大概 4.9MB 的可动静加载代码。

每个程序块都将被加载到内存中的固定地位。失去这个地位很麻烦,能够参考我的方法:

  1. 以十六进制关上程序块,找到大概前十六个字节。
  2. 在游戏加载这段程序块时,转储 RAM。
  3. 在 RAM 中搜寻这些字节,以找到它们在内存中的加载地位。

失去程序块在内存中的加载地位,就能够按如下形式将其加载到 Ghidra 中:

  1. 在 code browser 中,抉择 File – Add to Program 并抉择相干二进制文件。
  2. 点击“Options”。勾选“Overlay”,输出块名称,并输出相干的基址(请记住,对于 PSX,它以 8 而不是 0 开始)。
  3. Select Tools – Memory Map (or hit the icon on the toolbar). Select your overlay and ensure the following are ticked: R, X, Overlay, and Initialized.“X”is important as it determines executable.
    抉择 Tools – Memory Map(或点击工具栏上内存形态的图标)。抉择加载的程序块并确保选中以下项:R, X, Overlay, and Initialized。“X”很重要,它代表可执行文件。
  4. 双击起始地址。这应该会在代码浏览器中显示。
  5. Analysis – Auto Analysis 以反编译。

解决动静加载的另一个难点是,程序块有时在 CD-ROM 文件列表中未列出,因为只有主 EXE 能力被文件系统拜访。您必须查看主可执行代码,以查看加载到何处以及多少字节。或者,您能够从内存转储中提取它。

正文完
 0