做瑞芯微平台固件定制的人,估计都有过这种经历:官方固件用着还行,但内置应用删不掉、默认权限管不住、想给自己的工具开个 root 通道又不知道从哪儿下手。网上教程不少,可大多数只讲到“解包”就断篇了,真正到 root 提权和重打包烧录环节,全靠自己试错。这篇文章把我最近一次基于瑞芯微 RK3568 盒子固件做完整修改的过程整理出来,从拿到 update.img 开始,到最终把带 root 的固件烧回设备,把每一步的原理、命令、工具和坑位都摊开讲。
这套流程适用于大多数瑞芯微方案,比如 RK3288、RK3328、RK3399、RK3566/RK3568,不管你是给电视盒子做精简、给开发板调系统,还是给厂商定制 ROM,思路基本一致。整体分三块:先搞清楚瑞芯微固件的镜像结构和分区约定,再执行解包和重打包,最后处理 root 提权和烧录。省流版结论:瑞芯微固件修改的核心不是“拆”和“装”,而是理解 parameter 文件和 boot.img 的 ramdisk 机制,这两点搞懂了,工具只是辅助。
1. 解包前的必修课:瑞芯微固件的镜像结构与分区约定
1.1 update.img 不是“一个镜像”,而是一个打包容器
我刚接触瑞芯微时,第一反应是拿 7-Zip 直接解压 update.img,结果发现固件里看到的根本不是普通分区文件,而是一堆带偏移量的数据块。后来才明白,瑞芯微的 update.img 本质上是个容器格式,内部由 loader、parameter、分区镜像共同组成,所谓“解包”,就是把这些组成部分拆出来,而不是把分区里的文件系统直接释放成文件夹。
具体来说,一个典型的瑞芯微 update.img 包含以下部分:
- MiniLoaderAll.bin:一级引导加载器,负责初始化 DDR 和存储设备,严格来说它不属于 Android 分区,但烧录时排在前面。
- parameter.txt:分区布局表,记录每个分区的起始扇区、长度、路径和属性,是整个固件的“地图”。
- uboot.img:U-Boot,负责引导内核。
- boot.img:包含 kernel 和 ramdisk,Android 的 root 修改主要动它。
- dtbo.img / resource.img:设备树叠加和内核资源,RK3568 上还会涉及设备树覆盖。
- super.img(或 system.img / vendor.img):Android 系统分区和新版动态分区结构。
- vbmeta.img:AVB(Android Verified Boot)校验元数据,root 后如果不开机,多半是它没处理。
打包工具用到了 Rockchip 的 AFPTool 或专门拆包脚本。你只要记住,在解析 update.img 时,脚本会读取固件头里的“seek table”索引,挨个把分区镜像导出来,并同时生成一份 parameter 文件。很多教程里说的“解包固件”,其实指的是两步:先用拆包工具导出分区镜像,再用 simg2img 之类的工具处理 sparse image,最后挂载或释放分区的文件系统。
1.2 parameter 文件决定你怎么改、改成什么样
parameter 文件是瑞芯微固件区别于其他平台的关键。它本质是一个文本文件,里面定义了分区的 table。我的实践顺序是先打开 parameter 文件,对照分区名和数据块范围确认固件版本,再决定要不要动分区大小。举一个实际例子,RK3568 常见的 parameter 片段长这样:
FIRMWARE_VER: 1.0 MACHINE_MODEL: RK3568 MACHINE_ID: 007 MANUFACTURER: Rockchip CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(misc),0x00010000@0x00008000(boot),0x00010000@0x00018000(recovery),0x00040000@0x00028000(super),0x00002000@0x00068000(vbmeta),0x00002000@0x0006a000(security),0x00002000@0x0006c000(uboot_config),0x00040000@0x0006e000(device_tree),0x00002000@0x000ae000(metadata),0x00002000@0x000b0000(baseparamer),-@0x000b2000(userdata)看到这个别慌,逐段解释:0x00002000是分区长度,@后面的0x00004000是起始扇区地址,单位是 512 字节扇区。boot分区占了 0x10000 个扇区,换算下来是 32MB;super分区占了 0x40000 个扇区,也就是 128MB。后面-@表示剩余空间全部给 userdata。
做 root 修改时,我最常改的就是 boot 分区,一般并不需要调整 parameter 大小。但如果你要给 system 加应用或增大 vendor 分区,修改后必须保证所有分区镜像重新生成,否则烧录会提示“分区表与镜像不匹配”。还有个小技巧:把 parameter 文件单独拿出来保存,重打包后再塞回 container,能避免一部分烧录器设备读取到旧分区表的诡异问题。
1.3 boot.img 内部的 kernel/ramdisk 和 dtb 的关系
想顺利 root,得先把 boot.img 的内部结构看明白。标准的 Android boot.img 头里包含了 kernel 地址、ramdisk 地址、第二阶引导、设备树信息等字段。瑞芯微平台上 boot.img 常由三个实际部分拼起来:kernel 主体(zImage)、ramdisk 镜像(根文件系统)、DTB 设备树。
设备树在标题相关热词里被频繁点到,是因为 RK3568 这类芯片的显示、触摸、HDMI 输出参数全在设备树里。比如你想改 HDMI 分辨率、交换两个 USB 口的使能顺序,就得修改device_tree分区或resource.img内的 DTB,而不是去改 kernel 源码。不过初学阶段不用执着于设备树,root 的直接操作对象是 ramdisk:在ramdisk文件系统里放入 su 二进制、加入默认允许提权的策略、或者在 init.rc 里追加服务,这才是 root 的落地点。
2. 环境准备:主机工具链与设备驱动的三个容易踩坑的点
2.1 Linux 与 Windows 双环境下的工具分工
瑞芯微官方提供的工具跨平台有点分裂:解包和重打包多用 Linux 下的脚本或 Python 工具,烧录用 Windows 下的 RKDevTool。我个人的习惯是:在 Linux 虚拟机里做所有解包、文件操作、重打包,然后把最终生成的 update.img 放到 Windows 宿主机上跑烧录。这样分工有几个好处:
- Linux 侧处理 sparse image、挂载 ext4、修改文件权限,比 Windows 顺手太多。
- Windows 侧装瑞芯微 USB 驱动和 RKDevTool 更稳定,大部分盒子进入 loader 模式后,Windows 识别的兼容性更好。
- 减少在同一个系统里来回切换驱动和命令行工具导致的环境污染。
如果你用的是 WSL2,要注意一个很多人问过的问题:WSL2 本身在虚拟机化平台上运行,必须先在 BIOS/固件设置里打开 CPU 虚拟化,否则会报“此计算机上未启用虚拟化”。我之前就在一台老电脑上卡了半天,进 BIOS 开了 SVM 后才正常起来。但即便 WSL2 起来,我仍然不建议直接用 WSL2 去跑烧录工具,USB 设备透传虽然新版有支持,但 RKDevTool 这种图形化驱动工具出问题的概率不小。
2.2 驱动、短接方式与识别状态的判断
瑞芯微设备的烧录驱动是独立的,安装 RKDevTool 后,驱动不一定自动装好。Win10/Win11 下最稳的路径是:先把设备进入 Maskrom 模式或 Loader 模式,再接 USB 线,然后打开设备管理器,看是否出现Rockchip USB设备。如果出现感叹号,手动指向驱动目录安装一次。
所谓“进入 Loader 模式”,不同厂家的触发方式不一样。有的盒子在断电状态下按住机身上的恢复键再上电,有的需要短接主板上的两个触点。这里没有统一答案,只能看设备厂商资料。不过有个通行办法:用 adb 连接开机的设备,然后执行adb reboot loader,很多瑞芯微方案都接受这个命令直接进入烧录模式。如果 adb 没连上,再用按键或短接方案。
有人为了省事,直接在设备正常开机时点 RKDevTool 的“升级固件”,大多数时候也能成功,因为工具会自动让设备重启进入 loader。但遇到被修改过引导链路的固件,自动重启进 loader 可能失效,这时手动短路才是唯一解。
2.3 固件加密标志和签名校验的提前预案
瑞芯微的固件并不总是“裸奔”。新版工业级主板会开安全启动,固件里带 RSA 签名或 AES 加密标志。解包前怎么判断?可以用十六进制编辑器直接看 update.img 的开头字节,如果发现大量非RKASCII 字符或被明显压缩过的数据,多半带加密。
遇到加密固件,常规解包工具会直接报错。我的处理方式是:先查设备方案厂商是否提供“关闭安全启动”的配套固件或工具。比如部分 RK3568 核心板,厂商会给出一个带parameter且vbmeta状态为disabled的工程固件,这类固件可以直接二次解包。我在文章开头说过“适合大多数瑞芯微方案”,前提是你手里的固件不是加了强加密的定制版本。针对那种固件,研究重心要从“修改固件”转为“向厂商申请安全固件”,而不是逆向破解签名,这个边界要分清。
3. 固件解包实操:从 update.img 到可修改分区的完整链路
3.1 用拆包工具导出分区镜像和 parameter
假设你已经准备好了工具包,里面至少包括:
| 工具/文件 | 用途 | 备注 |
|---|---|---|
| update.img | 原始固件 | 必须与设备型号匹配 |
| 拆包脚本/AFPTool | 导出分区镜像 | 图形化工具或 Python 脚本均可 |
| parameter 解析工具 | 自动生成分区表 | 检查分区大小用 |
| simg2img | 转换 sparse image | Android 6 以上需要 |
| 镜像挂载工具 | 挂载 ext4 | Linux 下操作 |
以我常用的拆包脚本为例,执行后会把固件解到一个以Image或Output命名的目录里,里面通常能看到parameter.txt、MiniLoaderAll.bin、uboot.img、boot.img、vbmeta.img等文件。此时不要急着去动 boot.img,先把parameter.txt和misc分区检查一遍,因为有些厂商会自定义分区名,比如把super分成system、vendor、product三个独立镜像。如果你把分区名看错了,重打包后很容易导致烧录后系统起不来。
3.2 处理 sparse image:boot、super、vendor 的挂载方式
拿到分区镜像后,最常遇到的问题就是 sparse image(稀疏镜像)。Android 为了减少镜像体积,会使用 sparse 格式记录数据块,普通 mount 根本识别不了。转换方法很简单:
simg2img boot.img boot.img.raw mkdir /tmp/boot_part mount -o loop boot.img.raw /tmp/boot_partboot.img 解开后,你能直接看到 rootfs 的内容,比如init、init.rc、system/等目录。和传统嵌入式根文件系统不同,Android 的 ramdisk 用 cpio 格式打包,直接对着目录改完还得重新打包;如果想省事,可以在解包 boot 时使用专门的工具解开和合并 ramdisk:
# 解包 boot.img unpack_bootimg --boot_img boot.img --out boot_out # 解压 ramdisk cd boot_out/ramdisk gzip -dc ../ramdisk.img | cpio -i改完以后反向操作,再用打包工具把 kernel、ramdisk、dtb 重新拼回去。因为我之前没有记录每一步都重新生成一次 ramdisk 的习惯,结果到最后烧录时发现一个小改动没生效,排查了好久才意识到是打包顺序不对。所以强烈建议:每做一步修改,就单独把对应分区的 raw 镜像备份一次,并且用sha256sum记录哈希值。
super 分区的处理方式有所不同。动态分区结构下,super 内部还包含 system、vendor、product 等逻辑分区,建议直接使用lpunpack把逻辑分区解出来:
lpunpack super.img.raw super_out解出来的system_a.img、vendor_a.img之类的镜像继续通过simg2img转换后挂载。动手改 system 时,注意要给selinux权限策略留后路。root 后如果遇到 SELinux 拒绝服务,最简单的做法是把相关文件的安全上下文改成magisk或直接给目标进程打 permissive 标志,但这已经超出解包范畴,放到下一节细说。
3.3 修改分区内容:删预装应用、塞自己的可执行文件
解包后最常见诉求是删除预装应用。在 system 分区镜像挂载成功后,找到/system/app或/product/priv-app下的对应 APK 目录删除即可。但这里有个容易被忽略的限制:Android 10 以上采用动态分区+只读挂载,你改完的 system 分区镜像在重新打包后,如果保留 vbmeta 里的 AVB 校验,设备会检测到 system 被篡改而拒绝启动。处理方法是同时修改 vbmeta.img,或者用 Magisk 的方式保留 vbmeta 的 disabled 标志。
我还常在 boot 分区里加一个自己的调试脚本,比如在/init.rc中追加一段:
service my_init /system/bin/my_init.sh class main user root seclabel u:r:magisk:s0 oneshot这里用magisk的 SELinux 域,是为了避开部分系统对su守护进程的隔离限制。如果你不明白 seclabel 的含义,也可以先不加,直接在 ramdisk 的/sbin里放个静态编译的su文件,再改 init 的权限策略。后面我会专门讲 ramdisk 的 root 通道注入。
4. root 提权落地方案:修改 ramdisk 与处理后重启校验
4.1 两种 root 路线:传统 su 注入与 Magisk 修补 boot
瑞芯微平台上做 root,主流路线有两类:
- 传统方式:在 ramdisk 中放入
su二进制,并设置setuid root,再通过 init 脚本让su守护进程开机启动。 - Magisk 方式:用 Magisk 修补 boot.img,由 Magisk 在启动阶段自动接管 ramdisk,提供模块化 root 管理。
我推荐首选 Magisk,不是因为传统方式不好,而是 Magisk 处理 Android 高版本的方式更省心。传统 su 在 Android 7 以后会遇到 SELinux 和hidepid各种限制,Magisk 则会自动设置好magisk的 SELinux 域,还能通过 MagiskHide/DenyList 规避部分应用检测。瑞芯微平台的 boot.img 修补流程和手机平台一样,无非是把 boot.img 导出来上传到设备,再用 Magisk 应用选择“安装到 boot 分区”,最后把打补丁后的 boot.img 导回电脑。
4.2 在 boot.img 的 ramdisk 里直接注入 root 通道
有时我们拿不到 Magisk 可用环境,比如设备上没装 Magisk 应用,或者想在进入系统前就有一个 root 通道。这种情况下,直接在 ramdisk 里动手最可靠。流程是:
- 把 boot.img 解成 raw 镜像并挂载,提取 ramdisk。
- 解压 ramdisk,在
/sbin下放入一个预编译的su(静态链接,或依赖 lib 一并放进去)。 - 给
su设置 6755 权限。 - 修改
init.rc,在on post-fs阶段执行chown root:root /sbin/su和chmod 6755 /sbin/su。 - 重新创建 ramdisk 的 cpio 归档,重打包 boot.img。
可以把这一套理解成:你手动造了一个“默认允许所有应用请求 root”的入口。但要注意,这么做的安全性非常低,任何能进 adb shell 的人都能直接切换到 root。我在自己测试机上没问题,在交付给客户的机器上绝不这么干,还是加白名单和鉴权机制更稳妥。
4.3 处理 Android Verified Boot:vbmeta 与 dm-verity
瑞芯微平台从 Android 8 开始默认开启 AVB。即使 boot.img 被 Magisk 成功修补,启动时如果 vbmeta 里记录的 hash 和实际 boot 分区不匹配,系统会进入错误状态或无限重启。解决办法有两种:
- 将 vbmeta.img 替换成
vbmeta_disabled.img,让 AVB 整体跳过校验。 - 保留 vbmeta,但要加上
disable=1参数。重打包 vbmeta 时,工具会读取“DISABLE_VERITY”等标志并写入头部。
我实际测试中,RK3568 上最稳妥的是第二种方式:先备份原 vbmeta.img,然后修改其 flag 为 disable_verity、disable_verification,再重打包。这样 boot、system、vendor 分区的镜像被替换后也能正常启动,同时设备还能保留最基础的签名校验结构。
这里特别提醒一句:不要在升级固件之前忘记检查和还原 vbmeta。我有一次把 vbmeta 改成 disabled 后烧录,跑了一天,后来又要升级新固件,结果新固件里 vbmeta 是原版 enable 状态,刷完后旧 boot 和新 vbmeta 校验冲突,进了 recovery。最后还是重新用修改版 vbmeta 刷了一遍才开机。
4.4 我用什么工具确认 root 是否生效
烧录后最直接的开机验证方式是:
- 通过 adb 连接设备。
- 执行
adb shell。 - 输入
id,看 uid 是否为 0。 - 输入
su -c id,验证 su 能否正确切换。
如果输出里看到uid=0(root) gid=0(root),说明 root 通道已经打通。再进一步,检查getenforce的值,如果是Enforcing,说明 SELinux 还是强制模式。Magisk 通常会在启动时把部分进程置于magisk域,如果su被拒绝,试试把进程的 SELinux 模式临时设为 permissive:
setenforce 0做这一步前想清楚,permissive 模式会关闭整个系统的 SELinux 保护层,只适合调试,不适合长期运行。请在自己的测试设备上操作,不要在生产环境这么干。
5. 重打包与烧录:还原固件、确认 root 生效与变砖自救
5.1 把修改好的分区镜像重新塞回 update.img
重打包的操作和解包正好相反。你需要把修改后的 boot.img、system.img、vbmeta.img 等放回解包目录,然后用打包脚本遍历目录并生成新的update.img。核心还是参照解包时生成的parameter.txt,保持各个分区的排列顺序不变。如果某个分区的镜像尺寸超过了原分区大小,必须在打包前把它对应的 parameter 分区长度调大,否则工具不会报错,但烧录后分区表错乱。
这里有一个实操细节:解包工具和重打包工具必须匹配。小红书上很多旧教程用的 AFPTool 是新版工具,可以直接从一个解包目录生成 update.img;但如果你用的是 Linux 下的 Python 脚本,打包用的脚本参数和解包时可能不同,比如要显式指定 loader 文件路径。我建议全程每一步都写日志,记录用哪个版本的工具生成了哪些文件,避免重打包时用了旧 parameter 导致烧录失败。
5.2 烧录前检查:固件哈希、设备状态和备份
准备好新 update.img 后,先做一轮自查,这步能帮你省掉大量返工和变砖时间:
- 校验
update.img的 SHA256,确认和重打包完成时的文件一致。 - 对比新旧固件里的分区数量和名称,注意有没有误删分区。
- 给设备接上稳定电源,怕断电变砖的可以准备一个能承受烧录过程电流的适配器。
- 备份原固件和原分区镜像,最好放到另一个目录,防止刷完后悔。
烧录时选择 RKDevTool 的“升级固件”页面,加载 update.img 后点击“升级”。正常情况下,设备会自动进入 loader 模式并开始写入。写入过程中千万不要拔 USB,也不要断电。看到进度条走完并提示“升级成功”,再断开设备重启。
5.3 root 失败或开不了机的排查链路
我遇到最多的问题有两类:一类是烧录后卡 logo,另一类是能进系统但su不可用。
卡 logo 时,排查顺序是:
- 查 vbmeta:把刷入的 vbmeta 是否 disabled 和原始 vbmeta 对照。
- 查 boot 分区大小:看 Magisk 修补后的 boot 是否大于 parameter 里定义的大小。
- 查 ramdisk 打包格式:确认
ramdisk.cpio.gz压缩方式和原版一致。 - 查 kernel cmdline:有些设备需要在 parameter 的
CMDLINE里加androidboot.selinux=permissive才能绕开早期校验。
能进系统但 su 不可用时,优先看/system/bin/su或/sbin/su文件是否存在、权限是不是 6755,然后看 selinux 日志。推荐先用adb logcat | grep -i denied抓取被拒绝的 SELinux 记录,再看dmesg | grep -i avc,如果日志里出现avc: denied { execute } for pid=...,那就把目标域设为 permissive 或用audit2allow生成策略。
5.4 如何在另一台机器上复现整套流程
固件修改最怕环境差异导致结果不同。我在多台电脑上试过同样的工具包和流程,发现影响最大的是驱动版本和 USB 线缆质量。不要用“只能充电不能传数据”的线刷机,否则烧录会中途失败;读数工具和打包工具之间不要混用不同版本,否则可能出现“解包没问题、重打包失败”。
如果要在团队里复现,建议把整个工具链固定成一套,并记录版本号。我的方法是在项目目录下建一个README.md,把所有命令复制进去,注释写清每一步的输入输出文件。这样下次换机器只需要按文档执行,不用重新摸索。
6. 最后再聊一点经验:官方固件迭代时,如何快速适配 root
很多人修改完一套固件后,面对新版本固件又要推倒重来。实际上不用。瑞芯微固件的分区布局在同一系列芯片上通常变化不大,你完全可以只解包新版 update.img,替换掉旧版本的 boot.img 和 vbmeta.img,再把三个文件重打包。只要新老版本的 kernel 与 ramdisk 兼容,root 结果基本一致。
我现在的流程是:做一个固定的“root 修改工作目录”,里面放着已经验证过的 magisk_patched_boot.img 和 vbmeta_disabled.img,之后每次拿到新固件,只做两步——解包新版,把这两个现成文件塞进去;重打包,烧录。真正花时间的是第一次适配,后续基本都是机械操作。这也是为什么工具包比一次性教程更有价值:你可以把解包、root、重打包这三步封装成脚本,以后一键完成。
至于其他瑞芯微相关开发,比如 RK3568 设备树调整、Android Studio 调试 adb 权限等,都是在 root 基础上延伸出来的内容。先把固件链路走通,后面做开发效率会高很多。希望这篇文章能帮你少走一些我走过的弯路。