👁 46
这台小米盒子的 eMMC 已经整卡读出来了。型号 MDZ-26-AA——也就是 小米盒子 4S Pro(固件内部型号 MiTV-AZFP0),平台代号 frozen。SoC 是 晶晨 S905X3(Amlogic SM1),4 核 Cortex-A55 + Mali-G31;存储是 16 GB eMMC;系统停在 Android 9、内核 4.9.113。用户区一共切出 20 个分区,其中 18 个全挤在最前面 1.4 GiB 里。下面把硬件和固件分区摊开看一遍。

一、转储包与设备身份
转储是离线读的,包里就是整齐的几件东西:
xiaomiIPTVmaz-26-16G/ ├── BOOT1.BIN 4,194,304 B eMMC 硬件启动区 1 ├── BOOT2.BIN 4,194,304 B eMMC 硬件启动区 2(与 BOOT1 逐字节相同) ├── ECSD_CSD.BIN 544 B eMMC 扩展寄存器快照(ECSD) ├── RPMB.BIN 4,194,304 B RPMB 认证区备份 ├── UserData.BIN 15,634,268,160 B 用户区整镜像(14.56 GiB) ├── EMMC_Ghost.mpj 14,098 B 编程工程文件(含完整分区清单) ├── FileStatus.cfg 25,664 B 校验 / 状态元数据 └── P_log-sanxing 629 B 编程器运行日志(GBK 编码)
最有用的是 UserData.BIN——15,634,268,160 字节的用户区完整镜像。这个长度和 ECSD_CSD.BIN 里 SEC_C 寄存器读出的 30,535,680 × 512 B 完全一致,说明这份转储是完整、没有截断的。
| 项目 | 值 |
|---|---|
| 型号 | MDZ-26-AA(小米盒子 4S Pro) |
| 固件内部型号 | MiTV-AZFP0(ro.product.model) |
| 平台代号 | frozen(ro.product.device / board / platform 三处一致) |
| 品牌 / 类型 | Xiaomi · stb(机顶盒) |
| 系统 | Android 9(SDK 28)· 构建号 23.5.10.1035 |
| 内核 | Linux 4.9.113(32 位 armv7l) |
| 构建时间 | 2023-05-10(安全补丁日期 2022-01-01) |
二、硬件
2.1 硬件清单
| 项目 | 值 |
|---|---|
| SoC | Amlogic S905X3(SM1 平台,RevB) |
| CPU | 4 × Cortex-A55(MIDR 0x411fd050),32 位 |
| GPU | Mali-G31 MP2 |
| 内存 | 2 GB(aml_dt=sm1_ac214_2g,内核可见 2,097,152 K) |
| 存储 | 16 GB eMMC —— 三星 KLMAG1JETD-B041(产品代号 AJTD4R),eMMC 5.1,可用 14.6 GiB |
| Wi-Fi | RTL8821CU(USB 免驱方案) |
| 蓝牙 | Realtek rtk_btusb(USB),Core 2.22 |
| HDMI 输出 | hdmitx Ver 20190815,默认 1080p60 / RGB444 8bit,支持 HDCP 2.x |
| HDMI 输入 | hdmirx 驱动存在但 no hdmirx regs(未布线) |
| 显示 | framebuffer 1920×1080 / 32bpp,另叠 CVBS 输出 |
| USB | xhci-hcd(含 pegasus USB 网卡驱动) |
Wi-Fi 和蓝牙都是 USB 方案,射频没做进 SoC 板内——这是 2018–2019 那批 S905X/X3 盒子(尤其运营商定制机)的典型做法。
顺带一个外部交叉验证:2020 年 11 月社区拆解 4S Pro 的记录里,主板是 S905X3 + 2 GB DDR3 + 16 GB eMMC,Wi-Fi 模块标称 FN-LINK 6221S——6221S 正是 RTL8821CU 的模组型号,和这次转储里读到的 USB 免驱驱动完全对得上。
2.2 eMMC 与内存布局
eMMC 是三星的 KLMAG1JETD-B041(产品代号 AJTD4R),16 GB eMMC 5.1 规格。设备自己起机时就把这颗芯片打印了出来——mmcblk0: emmc:0001 AJTD4R 14.6 GiB,容量和型号都在这一行里。转储这边也对得上:BOOT1.BIN / BOOT2.BIN / RPMB.BIN 各 4,194,304 B(4 MiB),UserData.BIN 15,634,268,160 B,换算就是 14,910 MiB 用户区——16 GB 标称容量扣掉保留区之后的可用空间。
这颗芯片的 RPMB 是已启用状态:认证密钥已经烧写、写入受密钥保护,转储自带的编程器日志(P_log-sanxing)读到的是「已使用」而不是空白区。RPMB 不存用户数据,它是给 Keystore / DRM / 回滚计数用的防重放小存储,和「只写 userdata 能不能开机」直接相关,放到第六节说。
2 GB 内存里有约 704 MB 被划成 CMA(视频编解码零拷贝缓冲),常规可用约 1.28 GB。内核保留区长得是这样:
05000000-07400000 36 MiB linux,secmon ← 安全监视器常驻 07400000-07500000 1 MiB ramoops 57C00000-59C00000 32 MiB linux,vm0_cma 59C00000-5DC00000 64 MiB linux,vdin1_cma 5DC00000-61C00000 64 MiB linux,vdin0_cma 61C00000-75000000 308 MiB linux,codec_mm_cma ← 编解码 CMA(最大一块) 75000000-77800000 40 MiB linux,di_cma 77800000-7F800000 128 MiB linux,ion-dev 7F800000-80000000 8 MiB linux,meson-fb ← framebuffer
三、Amlogic MPT 分区表
Amlogic 不用 MBR,也不用 GPT,而是把分区表以私有格式写在 reserved 分区开头,叫 MPT(Media Partition Table)。在偏移 0x02400000 处能读到魔数 MPT\0 加版本号 01.00.00。把它解出来,20 个分区一目了然:
| # | 名称 | 起始偏移 | 大小 | 里面是什么 |
|---|---|---|---|---|
| 0 | bootloader | 0x00000000 | 4 MiB | 引导镜像(AMLSECU! 加密内核) |
| 1 | reserved | 0x02400000 | 64 MiB | Amlogic 私有 MPT 分区表就写在这 |
| 2 | cache | 0x06C00000 | 512 MiB | 缓存区 |
| 3 | env | 0x27400000 | 8 MiB | U-Boot 环境变量 |
| 4 | logo | 0x28400000 | 8 MiB | 开机图资源容器 AML_RES!(10 项) |
| 5 | recovery | 0x29400000 | 24 MiB | Recovery 内核 / 恢复镜像 |
| 6 | misc | 0x2B400000 | 8 MiB | 引导控制块(BCB),空 |
| 7 | dtbo | 0x2C400000 | 8 MiB | 设备树叠加层 |
| 8 | cri_data | 0x2D400000 | 8 MiB | 加密 / 密钥数据 |
| 9 | param | 0x2E400000 | 16 MiB | 引导参数 |
| 10 | boot | 0x2FC00000 | 16 MiB | 内核 + ramdisk |
| 11 | rsv | 0x31400000 | 16 MiB | 保留,全空 |
| 12 | metadata | 0x32C00000 | 16 MiB | 元数据(FDE / OTA) |
| 13 | vbmeta | 0x34400000 | 2 MiB | AVB 校验元数据(空壳) |
| 14 | tee | 0x34E00000 | 32 MiB | OP-TEE 可信执行环境 |
| 15 | factorydata | 0x37600000 | 10 MiB | 出厂数据 |
| 16 | vendor | 0x38800000 | 512 MiB | 厂商只读卷 ext4(卷标 vendor) |
| 17 | system | 0x59000000 | 1 GiB | Android 系统卷 ext4(卷标 /) |
| 18 | product | 0x99800000 | 32 MiB | 产品定制卷 |
| 19 | data | 0x9C000000 | 12414 MiB(12.1 GiB) | 用户数据 ext4(全盘加密 FDE) |
注:分区表里的 product 偏移原始报告写成 0x09980000,多了一个 0;按后一个分区 data 的偏移反推,正确值是 0x99800000。
3.1 布局规律:每个分区后面固定留 8 MiB
除了 bootloader → reserved 之间那个 32 MiB 空洞,其余每个分区之后都固定留 8 MiB 间隙。这些间隙不是浪费——它们是分区级的磨损均衡预留,保证擦除某个分区时不会波及相邻分区。整个镜像里 10.1% 的已擦除区域,绝大多数就落在这些间隙上。
3.2 三重自洽性验证
这份分区表不是猜的,有三条互相独立的证据能对上:
| 验证项 | 结果 |
|---|---|
| data.offset + data.size = 15,634,268,160 | = UserData.BIN 文件大小 ✔ |
| ECSD_CSD.BIN 的 SEC_C = 30,535,680 × 512 | = 15,634,268,160 ✔ |
| 内核 meson-mmc: 注册表(20 个 mmcblk0pNN) | 偏移 / 大小与 MPT 逐项吻合 ✔ |
四、三个 ext4 卷
20 个分区里只有三个是真正的文件系统(超级块在分区起点 +1024,magic 0xEF53):system、vendor、data。它们的空间占用情况是直接从超级块里读出来的:
| 卷 | 偏移 | 大小 | 总块数 | 空闲块 | 已用 | 卷标 |
|---|---|---|---|---|---|---|
| system | 0x59000000 | 1 GiB | 262,144 | 43,596 | 83.4% | /(根) |
| vendor | 0x38800000 | 512 MiB | 131,072 | 23,646 | 82.0% | vendor |
| data | 0x9C000000 | 12.1 GiB | 3,177,980 | 934,609 | 70.6% | (无卷标) |
三个卷都开了一组共同的 ext4 特性(CSUM_SEED、EXTENTS、64BIT、FLEX_BG、INLINE_DATA、DEFRAG);data 额外开了 EXT_ATTR、GDT_CSUM 和 QUOTA。SELinux 是启用的,system 里能直接看到 u:object_r:rootfs:s0 上下文串。
另外 system 和 vendor 的 UUID 生成方式不一样:vendor 的 UUID 第三段是 5901,属于 Android 用卷名 + 路径哈希出来的确定性 UUID;system 那边则是真随机 UUID。同一台机器上两种做法并存,是 mkfs 时机和参数不同造成的,属正常。
五、系统版本
系统身份直接从 /vendor 和 /system 的构建属性里读:
| 属性 | 值 |
|---|---|
| ro.build.fingerprint | Xiaomi/frozen/frozen:9/PPR1.180610.011/1035:user/release-keys |
| ro.build.version.release | 9(Android 9 Pie) |
| ro.build.version.sdk | 28 |
| ro.build.display.id | 23.5.10.1035(MiTV 商业版本号) |
| ro.build.version.security_patch | 2022-01-01 |
| ro.build.date | Wed May 10 17:57:03 CST 2023(构建机 c5-mitv-cm-build06.bj) |
| ro.product.cpu.abi | armeabi-v7a —— 只有 32 位 |
| ro.build.type / tags | user / release-keys |
内核是 Linux version 4.9.113-gc1ad0ff2cfbd-dirty,GCC 6.3.1 编的 32 位 SMP 内核(armv7l)。同一分区里还躺着另外两个内核构建变体(4.9.113-g0ba0888、4.9.113-g1ee05ea),来自另一台构建机——说明这个 BSP 分支同时挂着好几条并行构建流。
六、RPMB 与「只写 userdata 能不能开机」
这是整卡备份最常被问到的一句,答案可以直接给:同一台机器上、只把 UserData.BIN(用户区整镜像)写回去,能正常开机,数据也还在。前提有几条,先把这台机器的实际情况钉住:
| 项目 | 本机实况 |
|---|---|
| RPMB 区 | 4 MiB,已启用:认证密钥已烧写、写入受密钥保护 |
| 它的作用 | 给 Keystore / DRM / 回滚保护提供防重放计数,是安全小存储,不存用户数据 |
| userdata 加密 | FDE 全盘加密:ro.crypto.type = block: FDE device,AES-256-CTS |
| 密钥链位置 | data 分区尾部的 crypto footer(被包起来的主密钥)+ TEE/Keymaster 的硬件密钥(tee / cri_data 分区) |
为什么只写 userdata 不影响开机:
- 启动链根本不碰用户区。bootloader / reserved / boot / system / vendor 等 19 个分区全挤在最前面 1.4 GiB 里,写 userdata 时它们一个字节都不会变,引导流程原样。
- 解密密钥不在用户区里。FDE 的主密钥由 TEE/Keymaster 用硬件密钥包住,落在两条链上:data 尾部的 crypto footer + tee 里的 TEE。写回的是整段用户区镜像(footer 一起回来),而 tee / cri_data / metadata 都没动 —— 密钥链完整,开机照常解密挂载。
- RPMB 这一层压根没参与。开机只用最前面那 1.4 GiB 里的引导分区和 tee,RPMB 里存的是防重放计数与 DRM / Keystore 凭据,既不参与引导也不参与解密。只写 userdata 完全不碰它,RPMB 保持原样就是最安全的状态。
反过来,四条容易踩的坑:
- 别顺手把 RPMB.BIN 也写回去,尤其是别的机器、别的批次读出来的备份。这台机器的 RPMB 已经启用、带着密钥和单调写入计数:把别处的 RPMB 内容灌进去,计数一旦回退或者密钥对不上,RPMB 认证就不通过——表现通常是 Keystore 硬件密钥失效、DRM 掉级(比如 Widevine 掉出 L1)、个别应用要求重新登录甚至清数据,而不是简单回滚。既然只写 userdata 根本不碰它,就别多这一手。
- 只能写回原来那台机器。硬件密钥跟芯片绑定,换机只写 userdata 会解不开,Android 走「无法解密 → 清除数据」这条路:能开机,但数据归零。
- 必须写完整段。转储出来的是 14.56 GiB 的整块用户区,包含 data 分区尾部那段 crypto footer。如果只写「实际用到的 1884 MB」或者保存时截断,footer 一丢就再也解不开,只能格式化 data 重来(等于恢复出厂)。
- 别在写入中途断电。data 是 ext4 + 加密,写一半中断会留下不一致的文件系统,开机 fsck 可能过不去;这时最省事的处理就是格式化 data 让它重建。
一句话:只写 userdata 是这套转储里最安全的操作 —— 启动链和硬件密钥都不在用户区里,要守的规矩就三条:同一台机器、写完整段、别碰 RPMB。
七、顺带发现的几点
- 全盘加密是开着的:ro.crypto.type = block: FDE device,文件名加密用 aes-256-cts。也就是说 data 分区直接读出来是密文,转储本身不泄数据。
- ADB over TCP 默认端口 5555:service.adb.tcp.port 和 persist.adb.tcp.port 都写死 5555,但 ro.secure=1、ro.adb.secure=1、ro.debuggable=0,属于生产安全模式,默认连不上。
- 属性里有一处自相矛盾:system 里 ro.debuggable=0、ro.build.type=user,但 vendor 里同一组属性却是 ro.debuggable=1、userdebug/eng。多半是 vendor 镜像从 debug 分支裁出来忘了改回去,不影响使用,但在做完整性校验时是个明显的指纹。
需要提醒的是:这份转储的基线是 2018 年的 AOSP 9,安全补丁停在 2022 年 1 月。设备还在正常运行,但系统层面的漏洞是没人再补了——当存储载体或拆机研究没问题,别再拿它跑敏感业务。
数据来源:小米盒子 4S Pro(MDZ-26-AA,内部型号 MiTV-AZFP0)的 16 GB eMMC 整卡离线转储 (编程器读取,含 BOOT1/BOOT2/ECSD_CSD/RPMB/UserData 全套)· 分区表由 Amlogic MPT 结构解出,并与内核 meson-mmc 注册表、ECSD 的 SEC_C 寄存器交叉校验一致 · eMMC 型号取设备自身起机打印的 mmcblk0: emmc:0001 AJTD4R 14.6 GiB,RPMB 状态与容量取转储自带的编程器日志 P_log-sanxing(BOOT1/BOOT2/RPMB 各 4 MiB、用户区 14,910 MiB,与转储文件逐个吻合)。
💖 打赏支持
如果这篇文章帮到了你,欢迎打赏支持
微信扫一扫,赞赏支持
发表回复