前言

上中学的时候想听歌,二手收了一个自以为是 HiFi 播放器,现在来看实际上也就是个普通 MP3 设备的 EROS Q2 触屏版。这个产品看来比较冷门,之所以买它是因为原先有一个 EROS Q2 普通版,后来因为进水损坏了,也没想太多,就买了个二手的看起来像是“同型号增强版”的这台设备。

虽然 EROS Q2 触屏版顶着 EROS Q2 的名号,实际上和原来的产品应该是完全不一样的。触屏版应该是外包给海贝公司定制的产品,系统也就迭代了 1 版就废弃了。(怎么我手上都是这样的设备 (恼) 上一个是 OPPO Pad 1)

使用的过程中发现这外包产品果然是完全没有系统维护,Bug 不少,包括但不限于蓝牙卡顿,HiBy Connect 连接故障,歌词显示异常,播放界面卡死等等。后来高中毕业,上了大学,设备也就闲置了。这次放寒假回来因为需要蓝牙音乐转盘(蓝牙转 3.5mm),于是重新将这个设备从家里带了过来,准备尝试手动修修 Bug。这篇文章也就算是记录下对这个设备简单修改的流程了。

固件结构分析

升级包本身

由于定制版系统看起来并没有什么地方有调试入口,于是打算先从官网提供的固件升级包入手。意外发现,官网提供的固件压缩包提供了完整的系统分区和当前版本 svn 日志。包含内容如下:

1
2
 $ ls
kernel.bin  logo.bin  readme.txt  recovery.bin  system.ubifs  uboot.bin  update_md5.txt  update.upt

我们可以先从日志入手,看看能不能找到有用的信息:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# readme.txt

1.Build Time:
2021年 07月 25日 星期日 16:27:21 CST
2.System Log:
[b38e50931facaa7dab68efaf4457def2d9c02561] (Fri Jul 23 15:10:31 2021 +0800) <xrj>
Modified batter max volPath: .
Working Copy Root Path: /home/xrj/pj/x1000/platform/user/q2
URL: svn://192.168.1.8/apps_x1000/q2
Relative URL: ^/q2
Repository Root: svn://192.168.1.8/apps_x1000
Repository UUID: 0549248a-adae-432c-8f31-806146f283ad
Revision: 9461
Node Kind: directory
Schedule: normal
Last Changed Author: xieruijie
Last Changed Rev: 9461
Last Changed Date: 2021-07-25 16:23:40 +0800 (日, 25 7月 2021)

注意到工作目录存在一个 “X1000”,检索后排除 Intel 那个 X1000,可以基本断定该设备的处理器应该是 Ingenic X1000。后续得知处理器实际上是 Ingenic X1000E,与 X1000 的差别在于 LPDDR 大小翻了一倍,具备 64MB LPDDR。

结合固件升级包给出的 kernel.bin, system.ubifs 和 uboot.bin 可以大致推断该设备应该是运行 Linux 的嵌入式设备。

update.upt 解包

根据官网信息:

TF存储卡升级方法:将TF卡格式化成FAT32格式,将update.upt拷贝到TF卡的根目录下。

可以看到,实际上系统更新只需要使用到 update.upt 文件。

我们 file 一下这个 update.upt,系统返回如下:

1
update.upt: ISO 9660 CD-ROM filesystem data 'CDROM'

很好,原来这个 update.upt 就是一个 iso 文件。那么我们挂载一下这个 iso:

1
2
3
4
5
 $ sudo mount -o loop ./update.upt /mnt/iso/
mount: /mnt/iso: WARNING: source write-protected, mounted read-only.
 $ cd /mnt/iso
 $ ls
_gitigno  system.ubi  uboot.bin  uimage.bin  update.txt  version.txt

发现 iso 中包含 system.ubi,uboot.bin 和 uimage.bin,以及一些其他文件。

分析系统镜像

我们查看一下 update.txt。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# update.txt

kernel={
        name=kernel
        file_path=autoupdate/uimage.bin
        md5=bac55859760f470b0d097bad7febe40b
}

rootfs={
        name=rootfs
        full_upgrade=yes
        file_path=autoupdate/system.ubi
        md5=5216c1cd8859d44fb9c04c439b520083
}

可知,实际上用于刷入的文件就两个:system.ubiuimage.bin。其中 system.ubi 是 rootfs, uimage.bin 是 kernel。

对两个文件分别 file 一下:

1
2
3
4
 $ file system.ubi 
system.ubi: UBIfs image, sequence number 25762, length 4096, CRC 0xdcc7e932
 $ file uimage.bin 
uimage.bin: u-boot legacy uImage, Linux-3.10.14, Linux/MIPS, OS Kernel Image (gzip), 2456169 bytes, Sun Jul 25 08:26:07 2021, Load Address: 0X80010000, Entry Point: 0X803D1F20, Header CRC: 0XC275CE43, Data CRC: 0X3CB74BC9

可见 system.ubi 实际上并不是 UBI (Unsorted Block Images) 镜像,而已经是 UBIFS 镜像,只是名字命名成了 .ubi。 为了编辑镜像,我们将镜像文件整体复制到其他地方。然后利用 Python 工具 ubi_reader 将其保留权限 (加入 -k 参数) 解包,即可得到完整的 rootfs。1

1
2
3
4
 $ sudo uv tool run --from ubi_reader ubireader_extract_files -k iso/system.ubi 
 $ cd ubifs-root
 /ubifs-root$ ls
bin  data  dev  etc  firmware  home  init  lib  lib32  linuxrc  media  mnt  opt  proc  push.bat  root  run  sbin  sys  tmp  usr  var

后续实践还可以发现,系统更新程序并没有签名校验等,仅简单验证 md5 确保文件完整性,并验证 version.txt 中的设备型号避免混刷。基于此并结合厂商提供了完整分区,可得出厂商给予用户的权限非常大,高度支持用户 DIY,后续可开 root adb 同样印证了这点。

分析设备系统

查看 /etc/os-release,得知这是一个基于 Buildroot 构建的 Linux 系统。

1
2
3
4
5
6
# /etc/os-release
NAME=Buildroot
VERSION=2014.05-00012-gd40d476-dirty
ID=buildroot
VERSION_ID=2014.05
PRETTY_NAME="Buildroot 2014.05"

首先观察启动流程。进入 /etc/init.d

1
2
/ubifs-root/etc/init.d$ ls
K40network  K90adb  Khid  N0101logging  rcK  rcS  S10mdev  S15boot.sysctl  S20urandom  S30_mount_userdata  S39_recovery  S40bt_init  S50sys_server  S91_early_mount.sh  S92_03_start_music_player  S99__99__end

主要看到三个文件:

  • K90adb,根据名字内容可以发现这个系统存在 adb 调试工具,但未默认开启。
  • S30_mount_userdata,根据内容可以看到用户数据存储在另外一个分区中。恢复出厂设置应该就是清除这部分的数据。
  • S92_03_start_music_player,根据内容,系统本体播放器程序应当存储在了 /usr/bin/hiby_player

那么先进入 /usr。注意到存在一个目录叫作 /usr/resource

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/ubifs-root/usr/resource$ ls -l
total 88
-rwxr--r--. 1 1007 1016  1646 Jun  4  2021 audio_back.conf
-rwxr--r--. 1 1007 1016     1 Jun  4  2021 bt_more_than_192k_fail
-rwxr--r--. 1 1007 1016     9 Jun  4  2021 bt_name
drwxr-xr-x. 1 1007 1016    76 Jun  4  2021 coordinate
-rwxr--r--. 1 1007 1016     1 Jun  4  2021 dac_out_more_than_384k_fail
-rwxr--r--. 1 1007 1016   311 Jun  4  2021 diff_layout.txt
drwxr-xr-x. 1 1007 1016    20 Jun  4  2021 eula
drwxr-xr-x. 1 1007 1016    52 Jun  4  2021 fonts
drwxr-xr-x. 1 1007 1016   480 Jun  4  2021 hl_json
-rwxr--r--. 1 1007 1016     7 Jun  4  2021 hostname
drwxr-xr-x. 1 1007 1016    12 Jun  4  2021 layout
drwxr-xr-x. 1 1007 1016    76 Jun  4  2021 litegui
-rwxr--r--. 1 1007 1016  6284 Jun  4  2021 ot_devices.json
-rwxr--r--. 1 1007 1016   892 Jun  4  2021 province.txt
-rwxr--r--. 1 1007 1016 39463 Jun  4  2021 radio.txt
-rwxr--r--. 1 1007 1016    16 Jun  4  2021 region
-rwxr--r--. 1 1007 1016   898 Jun  4  2021 song_genre.ini
drwxr-xr-x. 1 1007 1016    88 Jun  4  2021 str
drwxr-xr-x. 1 1007 1016     0 Jun  4  2021 system_attribute
-rwxr--r--. 1 1007 1016  1044 Jun  4  2021 tidal_search_record
drwxr-xr-x. 1 1007 1016   560 Jun  4  2021 unicode

看来系统中主要的资源文件(包括 UI 布局, UI 资源,多语言,字体,配置等一些其他文件)都在这个文件夹中。
注意到存在一个 hostname 和 bt_name,分别读取这两个文件,发现尽管 bt_name 与本设备匹配,叫作 QII Touch,然而 hostname 居然叫作 HiBy R2。这就有意思了,看来这个系统,甚至整个设备,都很有可能是基于 HiBy R2 修改过来的。

进入海贝官网产品介绍页,找到 HiBy R2,果然,HiBy R2 和 EROS Q2 Touch 的 SoC,显示器分辨率和 DAC 芯片完全一致。然而 HiBy R2 具有 WiFi 功能,EROS Q2 Touch 则没有。但这也解释了为什么前面在 /usr/init.d 看到 network 相关信息,且 /firmware 目录下存在 wifimac.txt:EROS Q2 Touch 很大概率就是基于 HiBy R2 部分阉割而来。

尝试移植 HiBy R2 系统

那么思路就变得清晰了:外包产品系统维护欠缺很正常,或许我们可以把本家产品更新版本的系统移植过来直接使用,这样就省去各种逆向工作了!

前往海贝官网服务与支持页,找到 HiBy R2 固件下载,可以看到最新版本为 v1.4。官方提供的下载链接:

链接:https://pan.baidu.com/s/17LX-GcjX4d1lwwhhOn5Gjg 提取码:HIBY

下载过来解包,压缩包目录结构果然是和 EROS Q2 Touch 一样的,只不过 update.upt 名字变成了 r2.upt。前面提到,.upt 文件中还有一个 version.txt,该文件用于校验设备型号。原先的 name=r2 需要修改成 name=q2,否则无法刷入。

编辑好后,直接重新打包,改名为 update.upt 并刷入设备,发现可以启动,但启动速度很慢,且触摸屏失效。怀疑存在驱动问题。

观察前面的 rootfs 可知,该设备的驱动基本都直接编译进 Kernel。由于两台设备的高度相似,我们直接将 Kernel 镜像 (uimage.bin) 互换,再次打包刷入,成功开机且硬件一切正常,但蓝牙出现了问题。

修复蓝牙故障

前面提到,HiBy R2 具有 WiFi 功能且蓝牙版本为 5.0。作为对比,EROS Q2 Touch 的蓝牙版本是 4.2 且不具备 WiFi 功能,因此 EROS Q2 Touch 可能更换了无线射频芯片。通过分析两设备的 rootfs,可以看到 EROS Q2 Touch 相比 HiBy R2 在 /etc 目录下多了个 csr8811.psr,而 HiBy R2 则相应地在 /firmware 中多了以下三个文件:

1
fw_bcm43456c5_ag_apsta.bin  fw_bcm43456c5_ag.bin  nvram_ap6256.txt

简单搜索可以看到 CSR8811 是来自 Qualcomm 的蓝牙 4.2 射频芯片和基带 IC,而 AP6256 是来自 AMPAK 的一个具备完整 Wi-Fi 和蓝牙功能的模块。

那么就很简单了,将 CSR8811 的驱动添加到 HiBy R2 的 rootfs 中,并将 /usr/bin/ 中四个有关蓝牙初始化的脚本(bt_init, bt_done, bt_resume 和 bt_suspend)与 HiBy R2 中的简单进行替换即可。注意权限需一致,随后重新打包 ubifs,打包好 .upt 文件,启动系统,蓝牙完美驱动,同时也支持了 HiBy R2 的蓝牙 LDAC 功能。

需要注意的是,由于 EROS Q2 Touch 不具备 WiFi 射频模块,因此 HiBy R2 系统 UI 中提供的 WiFi 相关功能均不可用。这是预期行为。

开启 ADB

在最初分析启动流程时注意到具有一个 K90adb 文件,但系统中并没有明显的 adb 开关。最初我尝试直接修改 K90adbS90adb,成功开启 adb,此时设置中的 USB 模式变为 “底座”,但按钮开关并没有此选项,一旦切换成 “存储” 或 “音频”,就无法再换回去了。

查阅官方文档还可发现,其他更新版本的设备还存在 “多次点击版本号可开启开发者模式” 的功能,但在本设备上操作并没有开启。通过逆向 hiby_player 二进制程序,找到其实际上存在 Test mode 开关,实现逻辑为:打开关于界面后,点击 上方的 “关于” 标题 10 次即可开启测试模式,此时系统会执行 /etc/init.d/K90adb start 启动 adb。这时设备连接电脑即可看到已列出 adb 设备。执行 adb shell 就进入了这个设备的 Shell。

至此,我们成功将这个设备升级到最新系统并获取了 root 权限。


  1. 最完善的办法应该是模拟出一个 NAND 设备进行操作,但实现较为复杂,我为了偷懒就没做,因为保留权限地解包打包也能使设备正常工作。实际操作时应当时刻注意文件权限一致性。 ↩︎