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

本文详细分析了Anbernic RG35XX游戏设备的原厂固件结构,包括内核启动流程、自定义输入处理机制、模拟器修改方法,并提供了在Stock OS上编译SDL应用的完整工具链配置指南。

逆向工程RG35XX原厂固件

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

在我看来,原厂OS运行速度快且用户友好,但不可定制。不过很多人更喜欢Garlic OS,因为它能模拟更多游戏系统。

内核部分

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

有人曾成功从旧的S500设备编译内核并使GPU正常工作。RG35XX的Koriki系统基于该内核,但根据Discord上的信息,最新的Koriki版本使用了原厂内核。

设备没有可访问的串口和调试接口,因此尝试破解内核将是一个痛苦的过程。

RG35XX原厂系统启动序列

内核以uImage文件形式存储在第一个分区(FAT32)上。内置引导加载程序(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确实手动处理输入事件。

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

逆向工程

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

模拟器修改

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

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

为RG35XX原厂系统编译

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

对于编译器,从这里下载Linaro工具链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 设计