coremaze/ME2-Writeup

GitHub: coremaze/ME2-Writeup

通过逆向工程与漏洞利用恢复ME2设备固件通信协议,重建已废弃的USB接口功能。

Stars: 0 | Forks: 0

# 使用热风枪和刀具对 ME2 的 USB 进行逆向工程 ## 背景 2024 年,[bjiru 上传了一段关于 ME2 手持设备的视频](https://www.youtube.com/watch?v=vJjllNi0lMc),这是一款大约在 2008 年左右生产的玩具,其特点是可以通过 USB 在设备与在线世界之间同步积分和宝石。由于这款游戏非常小众,因此没有软件、驱动或资源被归档,至少在 bjiru 拿出在线游戏客户端之前是如此。 我是 [Miuchiz Reborn](https://miuchiz.com/) 的负责人,这是一项始于 2015 年的努力,旨在保存、逆向工程、[模拟](https://emiu2.miuchiz.com/)并维持一款类似游戏的活跃性,该游戏包含通过 USB 连接的在线部分和手持部分。由于年代相近且类型相似,ME2 早在 2018 年就已被 Miuchiz 社区注意到,他们(错误地)认为两者可能存在架构上的相似之处。尽管我多年来都知道这款设备的存在,但 bjiru 的视频最终促使我开始研究它。 我最初的努力全部集中在重建让 bjiru 的电脑游戏副本重新可用的服务器上,但在过程中,我的注意力不可避免地转向了手持设备。如果不实现与设备同步积分和宝石的机制,那么在线游戏的重建永远不可能完整。毕竟,电脑与 ME2 设备之间的通信正是游戏的核心噱头。我原以为凭借我之前处理 Miuchiz 手持设备的经验,可以很快理清它们期望的通信流程……只要我能获得一些代码用于逆向工程。 我的好奇心要求我牺牲掉 ME2。eBay 要求我付出法定货币。不久之后,这些样本就摆在了我面前。

ME2 Devices

这些是体积很小的设备,只有几个按钮和一个女性 mini-USB 接口。盒子里附带了一根电缆,但缺少安装软件和驱动的光盘。那个 USB 接口本应是用于在电脑和手持设备之间同步积分的途径,但当我开始研究 Miuchiz 手持设备时,我通过逆向工程其配套的 Windows 软件获得了对闪存存储的完全访问权限。由于 ME2 没有类似的软件,因此我没有任何可以逆向工程的内容来找出如何与设备通信。即使查阅了时光机和 bjiru 的资料,也显然没有留存下来任何可用的通信软件。我认为它叫做 ME2 Desktop Buddy,但这个应用程序与 bjiru 恢复的游戏客户端是分离的。手持设备本身会将其识别为可移动存储设备,但其中的内容只是引导你在线下载 ME2 游戏,而该游戏已不再可用。 前进的道路显而易见,因为只剩下唯一一条路可走:打开硬件。 ## 内部结构

ME2 PCB

主要的 ME2 固件存储在一块 SST39VF3201 闪存芯片上,容量为 2 兆字(4 兆字节,16 位可寻址单元)。主微控制器被……封装在一层硬环氧树脂下。这种结构被称为芯片载板(CoB),通常是一种节省成本的措施,但其副作用是隐藏了集成电路内部的所有识别信息。常规封装的芯片通常会有标识标记,就像这块闪存芯片一样。由于这类设备中使用的微控制器通常包含内部 ROM,因此有可能我需要逆向工程的 USB 代码就存在于那块 ROM 中。将代码保留在 ROM 中的好处是,它允许恢复变砖的设备,或者在制造商选择这么做的情况下,在组装后刷新设备。但那块 ROM 存在于我无法识别的芯片中。 从闪存芯片中检索数据是一个直接且有充分文档记录的过程:将芯片拆焊,放入 XGecu 等通用闪存编程器中,然后将其转储内容。如果我还需要获取微控制器 ROM 中的信息,那么过程会变得不那么直接,但对于这类不太可能具备保护机制的设备来说,仍然是可行的。过去,我在 Tamagotchi Pix 上向 SPI 闪存添加了代码,以便将其启动 ROM 复制到闪存芯片的空闲空间中,随后使用相同的闪存编程器读取。然而,在那种情况下,微控制器是常规封装且标有型号的,因此我可以找到其数据手册,了解其指令集以及 ROM 在内存空间中的位置。而此时,我完全缺乏 ME2 那块神秘芯片的任何信息。 ## 提取 尽管存在不确定性,但从目前来看,唯一可行的前进方式是拆焊闪存芯片。我也购买了一些闪存芯片插座,希望能将一个插座焊接到主板上。这样我就可以在需要时为它编写代码,以从微控制器中转储内部 ROM。 不幸的是,我无法在不损坏芯片的情况下用烙铁将闪存芯片取下。为了在多次失败尝试后解决这个技术难题,我购买了一个返工站(本质上是一个号称能达到 500 °C 的热风枪),并通过热空气熔化焊锡来移除芯片。这让我可以顺利转储闪存内容,但同时也发现实际上我无法使用购买的插座。我不仅要焊接 48 个微小引脚到主板上,还必须足够快地完成操作以避免熔化插座上的塑料。我既没有合适的工具,也没有相应的技能来处理这种情况,因此如果需要获取 ROM,我必须另寻他法。 不过,闪存转储看起来还不错,而且使用一个我专门为在固件转储中查找未压缩位图而构建的工具,我找到了通常会在设备上显示的图像:

Images in firmware dump

## 指令集发现 我已经获得了闪存芯片的固件转储,但在进行严肃逆向工程之前,至少需要知道设备运行的是什么指令集。硬件本身没有任何标识,因此只能猜测。我尝试在 [Ghidra](https://github.com/nationalsecurityagency/ghidra) 中分析代码,这是一个开源的反汇编器、反编译器和总是让我忙碌的麻烦工具,支持几乎所有处理器类型。ARM 变种?某种 6502 的衍生?MIPS?还是 Ghidra 支持的其他任何处理器?所有尝试都得到了响亮的“否”。 我尝试了所有方法,但没有任何结果能够反汇编这段代码。我知道这是代码,因为我甚至能找到我在寻找的代码片段!

USB code in hex editor

由于我过去在 Miuchiz 手持设备方面的经验,我对 USB 大容量存储设备的工作原理有一定了解。我识别出这段代码片段几乎可以肯定是在将 `'U', 'S', 'B', 'S'` 移动到某个位置,这是一种特定于我正在寻找的 USB 大容量存储通信的签名。我需要逆向工程的 USB 代码的某些或全部部分肯定存在于这个闪存转储中,但由于不知道它使用的是什么指令集,我无法对其进行反汇编。 此时,我手头有几个损坏的 ME2 设备。似乎很奇怪,但在环氧树脂块下面可能还有标记?可能没有,但在研究阶段,有时一个完全损毁的设备比一个只是损坏的设备更有价值。 好吧,我有一个热风枪和一把刀。正如他们所说,当你有一个热风枪和一把刀时,一切看起来都像……钉子?我觉得谚语是这么说的。

Chip-On-Board off board

将返工站设置为最高温度并用刀撬动后,整个环氧树脂块被移除。它的离开并没有在现在已不在板上的芯片载板下揭示任何标记。你可以看到微控制器硅晶片的背面,尽管环氧树脂中有一些气泡,透过它们可以看到连接线。 正如我所说,有时一个损毁的设备比一个损坏的设备更有价值,而我有一个热风枪、一把刀,以及迫切需要重温一下我的习语。

Microcontroller freed from its epoxy

哦。 哈? 我没想到可以用那种方式去封装一个 CoB。它干净利落地弹了出来,考虑到它的温度,我很高兴它没有朝我弹射。它非常漂亮,但实际上从这里可以继续前进。让我用电子显微镜再仔细看看。

User manual claiming that a digital microscope is an electron microscope

好吧,这就是它的用户手册所声称的。公平地说,我核实过,它确实包含[至少一个](https://en.wikipedia.org/wiki/One-electron_universe)电子。 在“拆解”其他玩具以寻找微小组件时,那些组件曾挑战我的视力,很明显我很少知道我的焊枪另一端到底发生了什么。一位朋友的非常有礼貌的建议让我购买了一款便宜的数字显微镜,原本是用于鉴定硬币和焊接的。

Poor quality die shot

尽管它并不真正适合这项工作,与它的用户手册声称相反,我还是用显微镜拍下了这张图像。它远不能用来辨认晶片上的任何文字,但整体布局是清晰的,我知道在哪里可以找到更多类似的图像。 [Siliconpr0n](https://siliconpr0n.org/),现在被称为 [Siliconprawn](https://siliconprawn.org/),有一个存档,其中许多人上传了晶片照片,尽管通常质量比我这张更好。不幸的是,仅凭我所掌握的信息,无法在该网站上进行有效的搜索,所以我开始点击、滚动并重复……

Matching die shot

它的指纹已被记录下来! 经过数小时,在凌晨 4 点,我终于发现了一些熟悉的东西。它的质量比我拍的好,但布局是毫无疑问的。它是一个 GPL162002A(或 B),旋转了 180 度,与 John McMaster 拍摄的匹配图像相比。它是一个 GeneralPlus 微控制器,它的资料表可以在网上找到,其指令集是 μ'nSP。 ## 固件逆向工程 μ'nSP 事实证明在同类玩具中相当常见,希望我能原谅我没有猜到这是一种指令集,其名称中包含的字符甚至不属于拉丁字母。尽管如此,它仍然足够小众,以至于 Ghidra 无法原生支持它。幸运的是,已经有[一些第三方工作](https://github.com/SamuelWAnderson45/ghidra-unSP)可供使用,因此我能够开始在 Ghidra 中进行反、命名函数,并从数据手册中导入寄存器名称。 下面是我非常确定就是 USB 代码的函数,仅从其十六进制转储就可以识别出来,它按照微控制器数据手册中指定的方式与 USB 寄存器交互:

USB function decompilation

正如我之前提到的,我已经对这类 USB 大容量存储设备如何通信有所了解,特别是因为我将我的 Miuchiz USB 库移植到了 macOS 上并使用了 libusb。USB 大容量存储设备本质上是通过隧道传输 SCSI 命令,而这些命令在网上都有详细文档。例如,有用于请求从设备读取或写入的命令。

SCSI dispatch function decompilation

然而,我知道一般来说,标准命令(如读取或写入)对我没有用处。这些是你的电脑已经知道如何执行的操作;它会发出这些命令来像操作普通可移动介质一样与设备交互。在这种情况下,读取命令只会检索包含帮助文件的文件系统,而写入命令则不会执行任何操作,因为设备不应该可写。这些命令并不是用来访问整个闪存芯片的;相反,它们只是一个用于帮助首次使用者的微型模拟 CD-ROM。 不过,有些命令 ID 被保留用于厂商想要实现的功能。在正常 ID 查找运行之前,会预先注入一些保留 ID 的处理程序。

Special commands decompilation

通过静态分析,我能够识别并命名我正在寻找的函数:读取、编程和擦除闪存。这些都是为 ME2(以及可能的其它 GeneralPlus 设备)实现的非标准命令,几乎肯定被原本随设备提供的软件和驱动所使用。你可以构造一个 USB 消息来触发这些路径中的任何一个。读取允许你从闪存中检索数据。编程允许你“编程”闪存。擦除允许你将闪存区域的全部位重置为 1,而当与编程命令结合使用时,可以执行完整的闪存写入,因为“编程”只能将位从 1 翻转为 0。每一个我感兴趣的定制命令都使用保留 ID 0xFF,后跟子命令 ID 以及操作所需的任何参数。 这些命令的确切结构对读者来说并不重要,但方法论才是关键。我使用 [libusb](https://libusb.info/)(实际上是 [rusb](https://crates.io/crates/rusb))来辅助所有通过 USB 的交互。这种方法允许你编写用户态代码来与 USB 设备通信,而不是编写一个新的驱动程序。 当 Windows 版的 ME2 软件从互联网上消失时,就好像这门语言的倒数第二个使用者去世了。从某种意义上说,ME2 手持设备变成了一个[终端发言者](https://en.wikipedia.org/wiki/Speaker_types#Terminal_speakers)。通过一点实验和有时正确的反编译阅读,我正在“读懂”它的心,学习它几乎灭绝的语言。当它回话时,我知道自己走在正确的道路上。 Č̶̯a̴̩͗n̵͉͆ ̴͍͠Ǐ̶̜ ̴͈͌h̷̙̔á̶͉v̸͈̽é̴̢ ̵͍͛a̵̞͝ ̴̤̉s̵̡͊ē̴̮c̸̭̅t̶̛͖o̸̡͠r̶̺̊ ̶̥̀ǫ̸̀f̸̦́ ̷̈́ͅỳ̷͎o̶̦̐u̵͙̚r̶͙͒ ̵̥̕f̸̡͝l̷͈̄a̶͍͋s̸̢̓h̸̗͝?̴̪̕ ……不?一定是我的口音。让我调整一下再问一次:我能获取闪存的一个扇区吗?下一个扇区呢?你愿意将扇区中的任意位编程吗?我能再次获取你的闪存,看看它是否已经改变吗?我敢要求你擦除一个扇区……并希望理解*具体是哪个*扇区需要被销毁? 一个接一个,我编写了代码来构建、填充并传输我需要 ME2 接收的消息。一旦我们达成共识,我让它发送给我两个闪存转储,分别包含不同数量的积分。在比较之后,我能够确定积分在闪存中的存储位置,并最终使用我的电脑修改它们!

Score on device that says 654321

事实上,只要不涉及擦除正在被 actively 使用的代码,我就可以使用这些命令对设备做任何我想做的事情。ME2 加入了我收藏的设备清单,这些设备在它们不该出现的地方显示着 Miuchiz Reborn 的标志,包括用来拍摄晶片照片的数字显微镜。

Several devices with the Miuchiz Reborn emblem hacked into them

## “内嵌” ROM 与“内嵌”漏洞 坦率地说,当我第一次尝试读取/写入闪存时,我有点鲁莽,因为我无法看到所有正在执行的代码。例如,有些代码会调用微控制器的内部 ROM,或者由 ROM 复制到 RAM 中的例程。我对其他函数的猜测是基于直接内存访问(DMA)寄存器的设置方式。例如,如果 DMA 设置为从 USB 缓冲区复制数据,那么它很可能是在使用这些数据来编程闪存,而不是从闪存读取。

SCSI erase function decompilation

这段代码调用了一个位于闪存之外的函数,因此它不会把自己“拉起来”,然后再把自己“拉回来”。你确实必须非常小心,以免把设备变砖。 相关内存区域由数据手册明确布局:

Memory layout from datasheet with "Embedded ROM" spelled "Embadded ROM"

有 128 千字的特别“内嵌”ROM,我目前还无法访问,这阻碍了我完全理解整个系统。 幸运的是,自定义闪存读取命令没有执行边界检查。这意味着,通过构造一个尝试从非常高的闪存地址读取的特别消息,你可以绕过微控制器的整个地址空间,最终回到起始位置。因为这赋予了任意读取的能力,这次我不需要编写任何设备端转储代码!所有内存都可以通过这个漏洞读取,于是我用它来读取“内嵌”ROM,并将其保存以供后续逆向工程。 掌握了全部内存后,我能够在 RAM 中找到设备的帧缓冲区,从而显示当时屏幕上显示的图像:

Framebuffer in RAM dump

我还可以通过参考数据手册中指定的位置,从设备的地址空间中读取通用输入/输出(GPIO)寄存器。通过每秒触发数十次这个漏洞,我实际上可以轮询按钮按键,并将其变成一个 USB 控制器(如果需要的话):([视频](Videos/embadded_buttons.mp4)) 在测试过程中,某个时刻我注意到闪存中有一个奇怪的修改值,它看起来甚至不是保存数据。

Diff showing 0xAA being written into flash

0x00AA(记住,这个系统的字长是 16 位)被写入了一个我未请求的闪存位置。有了“内嵌” ROM,我终于可以看到解释这一现象的代码。

Disassembly showing the code that causes the OOB write

这些闪存芯片通过写入特定偏移量来接收命令。与 RAM 不同,写入 RAM 会立即提交数据,闪存芯片只会将写入解释为命令的一部分,因此单个写入到闪存地址空间不足以实际更改任何数据。当一段代码想要编程闪存时,它会发出一系列多步骤命令,从写入 0xAA 到 0x5555 开始,以在目标地址写入期望的数据结束。 如果一个拥有太多空闲时间的用户(也许还有热风枪和一把刀)想到尝试探测设备的工作方式,他们可能会请求设备编程一个超出其闪存容量的扇区。处理器知道每一步,但闪存芯片并不知道。相反,那个最后的命令周期完全错过了闪存芯片的地址空间,因此闪存急切地等待着应该编程哪个值。 由于命令周期不同步,闪存将下一个命令的第一个周期误认为是上一个命令的最后一个周期,于是 0xAA 被编程到了 0x5555。8 位字节的等效地址是 0xAAAA,这正好对应了我的闪存转储中 0x00AA 被写入的位置。 这可能被用于任意写入,只要你能接受损坏那个特定的字,但设备已经被完全攻破,我并不感兴趣再弄坏更多设备。也许可以拯救这些设备,因为逆向工程“内嵌”ROM也显示它包含自己的 USB 处理器和闪存读取/编程/擦除实现。然而,我只有一次让 ROM 进入该状态(而不是启动闪存代码),之后再也没有成功过。根据 ROM 的反编译结果,我怀疑它依赖于一个被悬空(未连接)的 GPIO 端口,但我不确定。无论如何,我在这里的任务已经完成。 ## 最终成果与收获 这项恶作剧带来的最终成果是一个命令行工具,它可以: * 读取闪存 * 写入闪存 * 读取积分 * 设置积分 * 读取宝石 * 设置宝石 * 通过漏洞转储内存 * 通过漏洞监视按钮输入 这些内容连同游戏服务器代码和其他研究结果,都可以在 [ME2-Restoration](https://github.com/coremaze/ME2-Restoration/) 仓库中找到。由于实现细节已经公开,而且可能对普通读者来说并不有趣,因此本文中省略了具体技术细节,转而描述流程和方法。 更重要的是,这证明了原始电脑端软件并非严格必要,无法理解或保留其功能。即使官方软件已随时间消失,仍然有可能打开这个“黑盒”,从其硬件和固件中重建通信协议,恢复一个原本无法使用的接口。这不仅仅局限于 USB 接口,[请阅读我是如何让一个早已死亡的许可证服务器让一款十年前的矢量编辑器重获新生的](https://github.com/coremaze/Plasma-Writeup)。 这也是我第一次对集成电路进行去封装,因此为了表达应有的尊重,我购买了一台更好的显微镜,并且已经[将 GPL162002A/B 的最高质量照片贡献给了 Siliconprawn](https://miuchiz.com/),这里提供一个降低分辨率以适应网页浏览的预览版本:

High quality die shot

标签:bjiru, ME2, Miuchiz, USB接口, 云资产清单, 单片机, 可视化界面, 固件分析, 复古游戏, 威胁模拟, 嵌入式系统, 开源游戏, 引脚焊接, 怀旧游戏, 拆焊, 数据恢复, 游戏存档同步, 热风枪, 电子维修, 硬件逆向, 社区考古, 芯片提取, 视频修复, 设备通信, 逆向工程