逆向工程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的指令:
|
|
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)
我不打算继续开发这个。也许有人可以基于此制作更好的启动器。