设备型号:MagicBox2
系统版本:YunOS 3.0.6
固件版本:3.0.6-RS-20160831.0951
芯片平台:晶晨 S802-H(M8)
内存:1 GiB DDR3
存储:8G eMMC
U-Boot:U-boot-00000-g667d5c3(m8_mango_v1@667d5c32) (Jul 15 2015)
内核:Linux 3.10.33(uImage,lzo 压缩)
WiFi:Broadcom SDIO(dhd/bcmsdh_sdmmc)
🔒 脱敏声明:本文涉及设备唯一标识(MAC 地址、设备序列号)、内网 IP 配置等内容,均已替换为占位符或做模糊化处理。
env.img本身含这些信息,绝对不能公开分享。
读者在自己设备上操作时,也请注意不要将原始env.img或含敏感值的串口日志直接公开。
写在前面
上一篇 《天猫魔盒2(TMB300A)固件提取与备份》 记录了怎么把原厂固件完整备份出来。备份是手段,不是目的。真正想做的事,是在这台老盒子上做点魔改:精简系统、去掉不需要的服务、尝试第三方固件,或者至少让它在一个可控的环境里跑起来。
但魔改之前,得先搞清楚它内部是怎么运转的。启动链怎么走、安全校验卡在哪、system 里哪些组件是厂商定制、哪些服务可以安全移除——这些不弄清楚,刷机就是碰运气。
这篇文章就是逆向分析阶段的记录。和上一篇一样,它会随分析进度逐步补充,不会一次写完。
最终实测结果: 签名校验拦截机制 不好处理, 就不进一步深究了 (浪费时间)
前置条件:
- 完整的分区备份
- TTL 串口访问
- root shell
这三样在上一篇里已经齐了。
本文目标:
- 还原完整启动链,确认每一级的输入输出;
- 分析安全机制(Secure Boot、系统完整性校验)对魔改的实际约束;
- 拆解
system分区,定位厂商定制组件和可精简项; - 确认硬件驱动与内核模块的依赖关系,为第三方固件适配做准备。
边界:本文只做分析和记录,不涉及具体刷机操作。魔改实操留到下一篇。
一、设备与固件概览
1.1 硬件规格
| 项目 | 规格 |
|---|---|
| SoC | 晶晨 S802-H(M8),四核 Cortex-A9 |
| 内存 | 1 GiB DDR3,DDR clock 768MHz,1T mode |
| 存储 | 8G eMMC(SDIO Port C) |
| WiFi | Broadcom SDIO,dhd 驱动 |
| 电源管理 | RN5T618 |
| 电池管理 | AML1218(平台复用,盒子无电池) |
1.2 软件版本
| 项目 | 版本 |
|---|---|
| 系统 | YunOS 3.0.6 |
| 固件 | 3.0.6-RS-20160831.0951 |
| 内核 | Linux 3.10.33 |
| U-Boot | m8_mango_v1,2015-07-15 |
| 安全方案 | M8-RSA-1024 |
1.3 已备份分区
| 分区 | 大小 | 用途 |
|---|---|---|
bootloader |
4 MB | 引导程序 |
reserved |
64 MB | 厂商保留 |
cache |
640 MB | 缓存 |
env |
8 MB | U-Boot 环境变量 |
logo / logo1 |
16 MB × 2 | 开机画面 |
recovery |
32 MB | Recovery |
boot |
32 MB | 内核 + ramdisk |
system |
800 MB | 系统主体 |
data |
约 5.67 GB | 用户数据 |
mmcblk0boot0/1 |
4 MB × 2 | eMMC 硬件 Boot 分区 |
二、启动链分析
M8-RSA-1024 校验
TPL secure check pass"] B --> C["U-Boot
m8_mango_v1
2015-07-15"] C --> D["读取 boot 分区
imgread kernel boot"] D --> E{"Amlogic 私有签名校验"} E -->|通过| F["加载 kernel
Linux 3.10.33
uImage, lzo"] E -->|失败| X["Image secure check fail
show error logo
boot_hang=2"] F --> G["DTB
m8_mang_1g"] G --> H["ramdisk
解压挂载"] H --> I["init
/init"] I --> J["解析 init.rc
及 import 的 rc"] J --> K["YunOS 服务启动"] X --> L["Enter v2 usbburning mode
等待 USB 烧录恢复"] style E fill:#f9c74f,stroke:#333,stroke-width:2px style X fill:#e63946,color:#fff,stroke:#333,stroke-width:2px style L fill:#457b9d,color:#fff
2.1 从串口日志还原的完整启动链
根据恢复出厂后抓取的完整串口日志,启动链如下:
BL1 / TPL(M8-RSA-1024 校验)
→ U-Boot(m8_mango_v1,2015-07-15)
→ kernel Linux 3.10.33(uImage,lzo)
→ DTB(m8_mang_1g)
→ ramdisk → init → YunOS 服务
2.2 各阶段关键日志
BL1 / TPL 阶段
Boot From SDIO C
Aml log : M8-RSA-1024
Aml log : TPL secure check pass!
ucl decompress...pass
Boot from internal device 1st SDIO C
- 启动介质是 SDIO Port C 上的 eMMC;
- TPL 阶段有 M8-RSA-1024 安全校验,日志显示通过;
ucl decompress说明 TPL 是压缩存储的,启动时解压。
U-Boot 阶段
U-boot-00000-g667d5c3(m8_mango_v1@667d5c32) (Jul 15 2015 - 17:28:52)
clr h-ram
DRAM: 1 GiB
relocation Offset is: 2fec8000
- U-Boot 编译于 2015-07-15,代码标识
m8_mango_v1; - 内存 1 GiB,U-Boot 自身重定位偏移
0x2fec8000。
内核引导阶段
## Booting kernel from Legacy Image at 12000000 ...
Image Name: Linux-3.10.33
Image Type: ARM Linux Kernel Image (lzo compressed)
Data Size: 7813246 Bytes = 7.5 MiB
Load Address: 00208000
Entry Point: 00208000
Verifying Checksum ... OK
Ramdisk start addr = 0x12774800, len = 0x27bc87
Multi dtb detected, support 2 dtbs.
0 dtb: ... "m8_mang_1g"
1 dtb: ... "m8_mang_2g"
Find match dtb: 0
Flat device tree start addr = 0x129f1000, len = 0x4bda magic=0xedfe0dd0
Uncompressing Kernel Image ... OK
- 内核 Linux 3.10.33,uImage 格式,lzo 压缩;
- 加载地址和入口地址均为
0x00208000; - DTB 支持 1G 和 2G 两个变体,本机匹配
m8_mang_1g; - ramdisk 起始
0x12774800,长度0x27bc87; - DTB 起始
0x129f1000,长度0x4bda。
init 阶段(节选)
init: mount none to target failed
init: Before e2fsck_main...
init: After e2fsck_main...
SysFileCheck: do_alisec|Total time passed: 135ms||
init: data_integrity_guard main!
init: is_support_system_bak sup_sys_bak:0
init: cannot find '/system/bin/zram_mount.sh', disabling 'zram_mem'
init: cannot find '/system/bin/nvwa', disabling 'nvwa'
init: process 'aliyun_uuid', pid 1387 exited
SysFileCheck/data_integrity_guard是 YunOS 的系统文件完整性校验;zram_mount.sh、nvwa在 system 中缺失,相关服务被禁用;aliyun_uuid与阿里云账号 UUID 相关。
2.3 启动链分析要点
| 阶段 | 关键点 | 对魔改的影响 |
|---|---|---|
| BL1/TPL | M8-RSA-1024 校验 | 需确认校验范围,是否覆盖 bootloader 之后的镜像 |
| U-Boot | 分区表、环境变量、bootcmd | 可修改 env 调整启动参数,但需注意校验 |
| Kernel | 3.10.33,uImage | 第三方内核需匹配此版本或确认兼容性 |
| DTB | 双变体,1G/2G | 魔改时需保持 DTB 与硬件匹配 |
| init | SysFileCheck、alisec check-core-file | 修改 system 可能触发校验,需分析绕过或关闭方式 |
三、init 脚本加载树
环境变量"] A --> C["init.usb.rc
USB 通用配置"] A --> D["init.amlogic.rc
Amlogic 平台配置"] A --> E["init.trace.rc
内核 tracing"] A --> F["init.yunos.rc
YunOS 定制服务"] D --> G["init.amlogic.usb.rc
Amlogic USB"] D --> H["init.amlogic.board.rc
板级配置"] H --> I["mount /system rw
alisec check-core-file
remount /system ro"] style H fill:#f9c74f,stroke:#333,stroke-width:2px style I fill:#e63946,color:#fff,stroke:#333,stroke-width:2px
3.1 完整加载顺序
init.rc 头部 import 顺序:
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.trace.rc
import /init.yunos.rc
ro.hardware 在这台机器上是 amlogic,所以实际加载 init.amlogic.rc。而 init.amlogic.rc 又 import:
import init.amlogic.usb.rc
import init.amlogic.board.rc
完整加载树:
init.rc
├─ init.environ.rc 环境变量(PATH、BOOTCLASSPATH 等)
├─ init.usb.rc USB 通用配置
├─ init.amlogic.rc Amlogic 平台配置
│ ├─ init.amlogic.usb.rc Amlogic USB 配置
│ └─ init.amlogic.board.rc Amlogic 板级配置(含 SysFileCheck)
├─ init.trace.rc 内核 tracing 权限
└─ init.yunos.rc YunOS 定制服务
3.2 各文件职责
| 文件 | 职责 | 关键内容 |
|---|---|---|
init.environ.rc |
环境变量 | PATH、LD_LIBRARY_PATH、BOOTCLASSPATH(含 libyunos.jar) |
init.usb.rc |
USB 通用配置 | adb、mass_storage、mtp、ptp 等 USB 模式切换 |
init.amlogic.rc |
Amlogic 平台配置 | 视频/音频/HDMI/CPU 调频等大量 sysfs 权限设置 |
init.amlogic.usb.rc |
Amlogic USB 配置 | USB 序列号、mass_storage、mtp、ptp 模式 |
init.amlogic.board.rc |
板级配置 | /system 挂载 + alisec check-core-file + remount ro |
init.trace.rc |
内核 tracing | trace buffer 权限 |
init.yunos.rc |
YunOS 定制服务 | alitvsecureboot、aliyun_uuid、nvwa、ras-daemon 等 |
四、U-Boot 层分析
offset 0x0
size 0x400000"] P1["reserved
offset 0x2400000
size 0x4000000"] P2["cache
offset 0x6400000
size 0x28000000"] P3["env
offset 0x2e400000
size 0x800000"] P4["logo
0x2ec00000 / 0x1000000"] P5["logo1
0x2fc00000 / 0x1000000"] P6["recovery
0x30c00000 / 0x2000000"] P7["boot
0x32c00000 / 0x2000000"] P8["system
0x34c00000 / 0x32000000"] P9["data
0x66c00000 / 0x16b400000"] P0 --> P1 --> P2 --> P3 --> P4 --> P5 --> P6 --> P7 --> P8 --> P9 end style P7 fill:#f9c74f,stroke:#333,stroke-width:2px style P8 fill:#2a9d8f,color:#fff
4.1 分区表(U-Boot 视角)
Partition table get from SPL is :
name offset size flag
0: bootloader 0 400000 0
1: reserved 2400000 4000000 0
2: cache 6400000 28000000 2
3: env 2e400000 800000 0
4: logo 2ec00000 1000000 1
5: logo1 2fc00000 1000000 1
6: recovery 30c00000 2000000 1
7: boot 32c00000 2000000 1
8: system 34c00000 32000000 1
9: data 66c00000 16b400000 4
与 Linux 下 /proc/partitions 的 mmcblk0p1~p10 完全对应,U-Boot 视角多了 offset 和 flag:
offset是分区起始地址(十六进制);flag可能与分区属性有关(如是否可启动、是否加密),具体含义需结合晶晨平台文档确认;bootloader之后到reserved之间有 32 MB 空隙,与/proc/partitions中总块数和分区块数合计的差值吻合。
4.2 环境变量分析
env.img 通过 strings 提取后,得到完整的 U-Boot 环境变量。以下是与魔改和安全相关的关键项。
💡 完整查看方法:
strings env.img | head -100只能看到前 100 行,可能截断长变量。建议用strings env.img > env_full.txt保存完整输出,再用grep按关键词筛选。
启动参数(bootargs)
将 initargs 与 storeargs 拼接,实际传给内核的 bootargs 为:
init=/init console=ttyS0,115200n8 no_console_suspend vmalloc=300m quiet
ramoops.mem_address=0x04e00000 ramoops.mem_size=0x100000
ramoops.record_size=0x8000 ramoops.console_size=0x10000 storage=2
vdaccfg=... logo=osd1,loaded,... hdmimode=1080p50hz cvbsmode=576cvbs
androidboot.firstboot=0 hdmitx=...
关键结论:
- ❌ 没有
dm-verity/verify=参数:内核未启用块设备级完整性校验; - ❌ 没有
androidboot.selinux=enforcing:SELinux 状态不由 bootargs 强制指定; - ❌ 没有
androidboot.verifiedbootstate=:未传递 Verified Boot 状态。
这意味着修改 system 分区后,内核层大概率不会因完整性校验而拒绝挂载。SysFileCheck 是用户空间的点名校验,不是 dm-verity。
启动流程(bootcmd / storeboot)
bootcmd=run storeboot
storeboot=echo enter storeboot...; echo Booting...; if unifykey get usid; then setenv bootargs ${initargs} androidboot.serialno=${usid}; fi; imgread kernel boot ${loadaddr}; setenv bootm_mode boot; bootm; run recovery1;
unifykey get usid读取设备序列号,拼进bootargs的androidboot.serialno=(原始值不展示);imgread kernel boot读取 boot 分区并启动;- 启动失败时执行
recovery1(显示错误 logo,挂起)。
恢复与烧录通道
recovery_key=saradc open 0; if saradc get_in_range 0x0 0x50; then msleep 50; if saradc get_in_range 0x0 0x50; then setenv user_factoryreset true; save; run recovery; fi; fi
switch_bootmode=... if test ${reboot_mode} = factory_reset; then run recovery; ... usb_burning ... safe_mode ...
recovery_key通过 SAR ADC 检测某个通道电压,连续两次命中触发恢复出厂;reboot_mode决定启动路径:正常、恢复出厂、OTA 更新、USB 烧录、安全模式;usb_burning和sdc_burning是两条救砖通道,具体触发方式待确认。
设备唯一标识与网络配置(隐私相关)
🔒 脱敏声明:以下环境变量值已做脱敏处理,
ethaddr、ipaddr、serverip、gatewayip、usid等均为设备唯一标识或内部网络配置,原始值不公开。env.img本身含这些信息,绝对不能公开分享。
ethaddr=xx:xx:xx:xx:xx:xx
ipaddr=x.x.x.x
serverip=x.x.x.x
gatewayip=x.x.x.x
netmask=255.255.255.0
ethaddr是以太网 MAC 地址,属于设备唯一标识;ipaddr/serverip/gatewayip是产线或内网调试配置,暴露内部网络结构;storeboot中的usid是设备序列号,同样属于设备唯一标识,原始值不展示。
⚠️ 结论:
env.img含设备唯一标识和网络配置,绝对不能公开分享。之前文章中将env.img列为“可公开”是不准确的,已修正。
其他关键变量
| 变量 | 值 | 说明 |
|---|---|---|
aml_dt |
m8_mango_1g |
DTB 名称,与串口日志一致 |
bootdelay |
0 |
启动不等待按键,正常上电无法中断 U-Boot |
firstboot |
0 |
首次启动标志 |
store |
2 |
存储类型(eMMC) |
hdmimode |
1080p50hz |
默认 HDMI 输出模式 |
outputmode |
1080p50hz |
默认输出模式 |
cvbsmode |
576cvbs |
CVBS 输出模式 |
4.3 安全状态
Aml log : M8-RSA-1024
Aml log : Image secure check pass!
aml_keys: version 0 can not be init 3ff7368c
ERR(v2_common/optimus_download_key.c)L268:failed to query key state, rc 0, keyIsBurned=0
- 镜像通过了 RSA-1024 安全校验;
- 但
keyIsBurned=0说明 efuse 中没有烧录设备密钥。
关键结论(已由实测修正):keyIsBurned=0 只说明 efuse 中没有烧录设备密钥,不代表 boot 分区的签名校验被关闭。后续刷入 boot_new.img 的实测证明,U-Boot 仍然使用内置公钥校验 boot 分区内 kernel 的 Amlogic 私有签名。原“efuse 未烧录密钥可能允许重签名镜像”的推测被证伪。
五、内核与 boot.img 分析
5.1 内核信息
| 项目 | 值 |
|---|---|
| 版本 | Linux 3.10.33 |
| 格式 | uImage(Legacy Image) |
| 压缩 | lzo |
| 加载地址 | 0x00208000 |
| 入口地址 | 0x00208000 |
| 镜像大小 | 7,813,246 字节(约 7.5 MiB) |
| ramdisk 起始 | 0x12774800,长度 0x27bc87 |
| DTB 起始 | 0x129f1000,长度 0x4bda |
5.2 boot.img 格式
2048 字节
page size=2048"] K["kernel
7,813,310 字节
按 2048 对齐"] R["ramdisk
2,604,167 字节
按 2048 对齐"] S["second
43,008 字节
按 2048 对齐"] H --> K --> R --> S style H fill:#457b9d,color:#fff style K fill:#2a9d8f,color:#fff style R fill:#f9c74f,stroke:#333,stroke-width:2px style S fill:#e76f51,color:#fff
file boot.img:
Android bootimg, kernel (0x10008000), ramdisk (0x11000000), second stage (0x10f00000), page size: 2048
binwalk boot.img:
Android bootimg, kernel size: 7813310 bytes, kernel addr: 0x10008000, ramdisk size: 2604167 bytes, ramdisk addr: 0x11000000
| 项目 | 值 |
|---|---|
| 格式 | Android bootimg |
| page size | 2048 |
| kernel 大小 | 7,813,310 字节(约 7.45 MB) |
| kernel 头地址 | 0x10008000 |
| ramdisk 大小 | 2,604,167 字节(约 2.48 MB) |
| ramdisk 头地址 | 0x11000000 |
| second stage | 存在,地址 0x10f00000 |
5.3 头地址与串口日志加载地址的差异
串口日志里:
Load Address: 00208000
Entry Point: 00208000
Ramdisk start addr = 0x12774800
而 bootimg 头里 kernel addr 是 0x10008000,ramdisk addr 是 0x11000000。
解释:U-Boot 读取 bootimg 后,会把 kernel 和 ramdisk 重定位到实际运行地址。头里的地址是 bootimg 打包时的约定地址,U-Boot 根据内存布局重新搬运。所以 0x10008000 → 0x00208000、0x11000000 → 0x12774800 是 U-Boot 的行为,不是镜像损坏。
5.4 binwalk 扫出的内容
binwalk 在 boot.img 中扫出大量:
- ELF 32-bit LSB shared object, ARM:ramdisk 里的共享库和可执行文件;
- Copyright string:大量 Android Open Source Project 和 IBM 的版权字符串;
- WidevineMediaKit 路径:
/var/lib/jenkins/workspace/Android_Classic_Widevine/...,说明 ramdisk 里包含 Widevine DRM 组件; - 蓝牙配置:
/etc/bluetooth/bt_vendor.conf; - 证书:
/etc/ssl/certs/ca-certificates.crt; /usr/bin/ntlm_auth:网络认证工具。
💡
bix header、mcrypt 2.2 encrypted data等大概率是误报或加密数据,不必过度解读。
结论:ramdisk 里不只有 init 脚本,还塞了不少厂商预置的二进制和库。
5.5 boot.img 内核与 ramdisk 数据疑似加密
abootimg -x 能正常解出 zImage、initrd.img、bootimg.cfg,但 zImage 前 512 字节全是随机字节,没有任何可读字符串:
00000000: 4d7a 6919 3461 6608 5ba2 114d c758 ee1b Mzi.4af.[..M.X..
00000010: 0a56 3522 4c6f 5ddf f6e1 8d89 fda9 5565 .V5"Lo].......Ue
...
标准 uImage magic 是 27 05 19 56,gzip 是 1f 8b,ELF 是 7f 45 4c 46,前 512 字节里都没有出现。initrd.img 同样全是随机字节,file 返回 data,binwalk 无识别结果。
判断:boot.img 里的 kernel 和 ramdisk 数据很可能被 Amlogic 私有加密或加扰。bootimg.cfg 中的地址和大小与串口日志一致,说明 abootimg 切分偏移没错,只是内容不是明文。
keyIsBurned=0 只说明 efuse 中未烧录设备密钥,不代表镜像本身未加密——加密密钥可能硬编码在 BL1/U-Boot 中。
直接解包尝试结果:
Customization Tool10.1.0 在部分 Windows 环境下启动闪退,无法使用。论坛中也有其他用户报告类似问题,换机器或换版本不一定能解决。mkbootimg_tools的mkboot脚本成功识别了 bootimg 头部(kernel 大小 7813310、ramdisk 大小 2604167、page size 2048 等),但最后报错ramdisk is unknown format, can't unpack ramdisk。- 公开工具
abootimg、unpackbootimg、mkboot均无法解包此 ramdisk,确认 Amlogic 对 ramdisk 数据做了私有封装或加密处理。
对魔改的影响:
- 不能直接用标准
abootimg/unpackbootimg/mkboot解包和重打包; - 不建议在逆向加密算法上投入过多时间,目标不是“解析原厂 ramdisk”,而是“让修改后的系统能启动”;
- 更实际的路线是从运行系统重建 ramdisk。
5.6 second stage 实测结论与文件取舍
abootimg -i 报告的 second stage size = 2604167 与 ramdisk size 完全相同,这个值不可靠。实际提取结果:
| 工具 | 文件 | 大小 | md5 |
|---|---|---|---|
abootimg -x |
stage2.img |
42 KB | ffa699b7bc23daec92da4765db819d90 |
mkboot |
second.img |
42 KB | ca930f1535689e9aada383cc2ec5372e |
| Python 按 42 KB 偏移切分 | second_42k.bin |
43008 字节 | ca930f1535689e9aada383cc2ec5372e |
mkboot 和 Python 切分结果完全一致,互相印证,说明 second 的真实大小是 43008 字节(42 KB),内容以这两个为准。abootimg 虽然也切出 42 KB,但内容不同,说明它对 Amlogic 私有 bootimg 的 second 偏移解析有偏差,stage2.img 不可用。
关于 mkboot 报错的说明:mkboot 解包时报告 ramdisk is unknown format, can't unpack ramdisk,这个错误发生在“尝试解压 ramdisk”阶段,不影响前面的“按 header 偏移切分 kernel、ramdisk、second”步骤。second.img 在报错之前就已经切好,且与 Python 按标准 bootimg 布局独立切出的结果 md5 完全一致,说明 mkboot 的 second 切分是正确的。
关于 second.img.tmp:mkboot 解包后会同时留下 second.img 和 second.img.tmp。.tmp 是工具“先写临时文件再改名”的中间产物,second.img 已正常生成,说明 second 切分完成。重打包用 second.img,不要用 .tmp。
second stage 只能从 boot.img 里切:second 区域不像 ramdisk 那样会在运行时解压挂载,内核启动时也没有使用它(/proc/cmdline 无相关参数,dmesg 只有 Freeing initrd memory),所以运行时无法导出 second,只能从原厂 boot.img 里按偏移切出。
5.7 从运行系统重建 ramdisk
原始 boot.img 中的 kernel 和 ramdisk 数据被 Amlogic 私有封装或加密,标准工具无法直接解包。但魔盒能正常启动,说明内核已经成功解压了 ramdisk,运行系统里的根文件系统就是 ramdisk 的内容。
重建 ramdisk 的完整流程如下。
前置确认
id
ls -la /init
ls -la /sbin
mount | grep -E '/system|/sbin|rootfs'
确认 root 权限、/init 是 ELF、/sbin 内容正常、rootfs 已挂载。
准备临时根目录
U 盘通常是 fuseblk(NTFS/exFAT),不支持符号链接,直接在 U 盘上 cp -a /sbin 会报 cp: symlink: ../init: Function not implemented。因此改为在 /data(ext4)下操作,最后只把生成的 cpio 文件复制到 U 盘:
rm -rf /data/local/rd_root
mkdir -p /data/local/rd_root
cd /data/local/rd_root
cp -f /init /init.rc /init.amlogic.rc /init.amlogic.board.rc /init.amlogic.usb.rc \
/init.environ.rc /init.trace.rc /init.usb.rc /init.yunos.rc \
/default.prop /file_contexts /file_manifest /file_whitelist \
/property_contexts /restart_info.png /restore_info.rle . 2>&1
mkdir -p sbin
cd /sbin
find . \( -type f -o -type l \) | while read f; do
mkdir -p "/data/local/rd_root/sbin/$(dirname "$f")"
cp -a "$f" "/data/local/rd_root/sbin/$f" 2>/dev/null
done
ls -la /data/local/rd_root/sbin/
预期看到 adbd、alitvsecureboot、healthd,以及 ueventd -> ../init、watchdogd -> ../init 两个软链接。
一次性 cpio 打包
cd /data/local/rd_root
find . | cpio -o -H newc 2>/dev/null | gzip > /data/local/ramdisk_new.cpio.gz
ls -lh /data/local/ramdisk_new.cpio.gz
cp /data/local/ramdisk_new.cpio.gz /storage/external_storage/sda1/
ls -lh /storage/external_storage/sda1/ramdisk_new.cpio.gz
预期文件大小在 1–3 MB 量级,接近原厂 ramdisk 的 2.48 MB。
校验归档内容
gunzip -c /data/local/ramdisk_new.cpio.gz | cpio -it 2>/dev/null | grep sbin
预期看到 ./sbin/adbd、./sbin/alitvsecureboot、./sbin/healthd、./sbin/ueventd、./sbin/watchdogd。
拉到电脑
adb pull /storage/external_storage/sda1/ramdisk_new.cpio.gz
5.8 重打包 boot.img
用系统 apt 安装的 mkbootimg 重打包。注意 Debian 源里的 mkbootimg(29.0.6)使用 --base + --kernel_offset 风格,不支持直接指定 --kernel_addr 这类绝对地址:
mkbootimg \
--kernel ~/boot_unpacked/zImage \
--ramdisk /path/to/ramdisk_new.cpio.gz \
--second ~/boot_mkboot/second.img \
--base 0x10000000 \
--kernel_offset 0x00008000 \
--ramdisk_offset 0x01000000 \
--second_offset 0x00f00000 \
--tags_offset 0x00000100 \
--pagesize 2048 \
-o boot_new.img
生成后校验:
file boot_new.img
abootimg -i boot_new.img
file 应显示 Android bootimg,abootimg -i 里 kernel size 应为 7813310,ramdisk size 应与 ramdisk_new.cpio.gz 大小一致。
打包结果确认:boot_new.img 生成后,file 和 abootimg -i 输出如下:
boot_new.img: Android bootimg, kernel (0x10008000), ramdisk (0x11000000), second stage (0x10f00000), page size: 2048
- kernel size 7813310,与原厂一致;
- ramdisk size 1334740(约 1.27 MB),对应新生成的
ramdisk_new.cpio.gz; abootimg -i报告的 second stage size 1334740 是已知误读(把 ramdisk size 读成了 second size),实际 second 数据是打包时传入的 42 KBsecond.img。以file输出为准。
ramdisk 从原厂 2.48 MB 缩小到 1.27 MB,是正常现象:原厂 ramdisk 是加密/私有封装格式且包含 Widevine、蓝牙、证书等组件,新 ramdisk 只包含 init 脚本和 /sbin,标准 gzip cpio 压缩后体积更小。
工具职责区分:Debian apt 安装的 mkbootimg 只负责打包,不包含可用的解包功能。解包 boot.img 仍需使用 mkboot(mkbootimg_tools)或 abootimg。虽然 mkboot 解压 ramdisk 会报错,但它切分 kernel、second 的功能是正常的,且与 Python 独立切分结果一致。流程是:mkboot 解包 → 替换 ramdisk → mkbootimg 打包。
mkbootimg_tools 的兼容性:该工具目录下的 mkbootimg 是 2016 年编译的 32 位 x86 ELF 二进制,依赖 /lib/ld-linux.so.2。在 64 位 Debian 12 上直接执行会报“无法执行:找不到需要的文件”。如果确实要用,需先 sudo dpkg --add-architecture i386 && sudo apt install libc6:i386,但旧二进制对新版 glibc 的兼容性不保证。推荐直接使用系统 apt 安装的 mkbootimg(29.0.6)。
5.9 刷入 boot_new.img 的实测结果:签名校验拦截
通过 update.exe(Amlogic USB 烧录工具的命令行版)将 boot_new.img 写入 boot 分区。烧录过程成功:
update.exe partition boot boot_new.img
file size is 0x8c5000
Downloading....
[update]:mwrite success
串口同步显示 Burn complete。但设备重启后,U-Boot 拒绝加载新 boot:
enter storeboot...
Booting...
error: image data is not a fdt
key_unify_init:362,unify key config table parse fail
Err key(L48):fail in key_drv_init
Aml log : M8-RSA-1024
Aml log : ERROR! Image secure check fail!
Error! Illegal kernel image, please check!
handle_error_proc, bootm_mode="boot"
show error logo...
show_booterror_logo, boot_hang="2"
关键结论:
Image secure check fail表明 U-Boot 对 boot 分区内的 kernel 镜像执行了 Amlogic RSA-1024 签名校验,mkbootimg生成的标准 Android bootimg 没有 Amlogic 私有签名块,被拒绝;keyIsBurned=0只说明 efuse 中未烧录设备密钥,不代表签名校验被关闭。U-Boot 仍然使用内置公钥校验镜像签名;- 之前“efuse 未烧录密钥可能允许
root shell dd"] --> C["boot.img 备份 A"] B["update.exe mread
USB 烧录模式"] --> D["boot.img 备份 B"] C --> E{"哈希比对"} D --> E E -->|一致| F["交叉验证通过
备份可信"] E -->|不一致| G["排查偏移或分区"] style F fill:#2a9d8f,color:#fff style E fill:#f9c74f,stroke:#333,stroke-width:2px