RG35XX原厂固件逆向工程深度解析

本文详细解析了Anbernic RG35XX复古游戏设备的原厂固件逆向工程过程,包括启动序列分析、内核架构研究、输入处理机制逆向,以及如何为该封闭系统编译自定义应用程序的完整技术方案。

逆向工程RG35XX原厂固件

朋友给了我一个Anbernic RG35XX进行破解。这是一个复古游戏设备(专门用于模拟老式游戏主机)。它附带两个操作系统:原厂OS和Garlic OS。原厂OS是闭源的,而Garlic OS是开源的,除了内核部分(全部都是闭源)。你可以通过菜单在两个OS之间切换。

原厂OS启动我的自定义二进制文件

在我看来,原厂OS速度快且相当用户友好,但不可定制,尽管许多人更喜欢Garlic OS,因为它可以模拟更多系统。

内核部分

Anbernic不会发布ATM7039S的源代码,而且找不到该SOC的数据手册。与原厂RG35XX OS相比,Garlic OS使用的内核略有不同。

有人能够从旧的S500设备编译内核并使GPU工作。RG35XX的Koriki基于此内核,但根据Discord中的信息,最新的Koriki版本使用了原厂内核。

没有可访问的串口和调试接口,因此尝试破解内核将是一次痛苦的经历。

RG35XX原厂启动序列

内核以uImage文件形式存储在第一分区(FAT32)上。内置的bootloader(u-boot)将引导加载此文件,并挂载ramdisk.img。在ramdisk.img内部,我们可以找到:/init、/init.rc、loadapp.sh。内核将启动基于Android init的/init(它使用bionic libc)。/init将加载/init.rc,在最后几行包含启动loadapp.sh的指令:

1
2
service loadapp /system/bin/logwrapper /loadapp.sh
class core

loadapp.sh将加载/system/dmenu/dmenu_ln。dmenu_ln可以在第二分区(ext4)找到,这只是一个shell脚本,将启动同样位于第二分区的/mnt/vendor/bin/dmenu.bin。

dmenu.bin是操作系统的主shell。这是使用SDL1.2用C语言编写的,但它使用自定义输入处理而不是SDL_WaitEvent。

自定义输入处理

有些人坚信原厂RG35XX OS中的输入处理比其他替代OS更快。我感受不到,但原厂OS确实手动处理输入事件。

为了逆向工程其工作原理,我使用Ghidra。由于这不是安全相关软件,没有保护或混淆,因此代码可以很干净地反编译。

逆向工程

它首先打开/dev/input/来查找名称为gpio-keys-polled的设备(此名称通过使用EVIOCGNAME请求的ioctl调用获得)。然后,它将启动一个线程(使用pthread)来轮询此设备。电源按钮是与所有其他按钮分开的设备,而重置按钮(在电源按钮下方)硬连线以重置控制台。

模拟器修改

在第二分区的appres/bin/game内部,我们可以看到每个模拟器的几个二进制文件。所有这些都已被Anbernic修改:

  • 它们使用自定义错误处理
  • 菜单按钮设置为显示菜单(因此所有模拟器具有相同的界面)
  • 添加了在C语言中实现的视频滤镜效果(如点阵)(不使用GPU)

为RG35XX原厂OS编译

通常,我们需要SDK来编译应用程序,但由于我们知道目标架构、调用约定和使用的库,我们可以解决这个问题。要编译将在原厂OS上运行的简单SDL应用程序,我们需要编译器、头文件和一些库。

对于编译器,从这里下载Linaro toolchain 4.7(最接近系统上现有的二进制文件)(选择gnueabihf): https://releases.linaro.org/archive/12.11/components/toolchain/binaries/

对于头文件,下载最新的SDL1.2并使用默认的SDL配置。对于库,我们可以使用第二分区上/lib中的文件。删除libc.so和libm.so,这两个是bionic文件,会导致错误。然后,添加来自usr/local/lib/arm-linux-gnueabihf的文件(也来自第二分区)。

然后,你应该能够手动编译所有内容。

输出到stdout/stderr将不可见,因此使用dup2将这些重定向到文件。

小型演示应用程序

在此存储库中,你可以看到我的小型演示应用程序。我包含了所有库,以便任何人都可以轻松开始(请在Makefile中将CC路径更改为你的安装目录)。 https://github.com/yohanes/rg35xx-stock-sdl-demo

这是一个非常简单的应用程序,用于替换dmenu.bin(请将原始dmenu.bin重命名为orig.bin),它只提供三个功能:

  • 测试按键事件
  • 启动ADB(用于传输文件和调试),我包含了自己的ADB_ON.sh,需要复制到与dmenu.bin相同的位置
  • 启动原始启动器(现在命名为orig.bin)

我不打算开发这个。也许有人可以基于此制作更好的启动器。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计