资讯动态

Android system.img解包重打包工具链实战指南

发布时间:2026/10/18 19:31:46 来源:尧图企业网站定制
简介本资源是一套开箱即用的Android系统镜像处理工具集专为Android系统开发者、ROM定制者及嵌入式调试工程师设计解决系统镜像解包、打包、稀疏格式转换与ext4文件系统构建等核心需求。压缩包共含4个已编译可执行文件img2simg.img转.simg稀疏镜像、simg2img反向转换、make_ext4fs生成ext4分区镜像及mkuserimg.sh整合用户镜像的Shell脚本覆盖从单一分区操作到完整系统镜像组装的全流程。包体仅136KB轻量高效无需额外编译或依赖环境适配主流Linux平台。目前已有2951人学习下载是快速上手Android底层镜像分析与定制的实用型工具包尤其适合需要反复验证分区结构、调试刷机流程或逆向分析厂商固件的技术人员。1. 这不是“安卓刷机包解包神器”而是一套被反复验证过的、能真正跑通从 system.img 解包到重打包全流程的底层工具链你是不是也试过下载一个号称“一键解包”的GUI工具双击运行后弹出报错libstdc.so.6: version GLIBCXX_3.4.29 not found或者用某脚本把system.img拆成目录改完build.prop后却卡在make_ext4fs报Invalid argument查半天发现是 block size 不匹配又或者simg2img转出来的镜像用mount -o loop挂载失败dmesg里只有一行VFS: Cant find ext4 filesystem—— 其实根本不是文件系统损坏而是你手里的simg2img版本压根不支持 Android 12 引入的sparse format v2。这套工具集不是玩具它包含四个经过真实产线验证的二进制img2simg将普通 ext4 镜像转为 sparse 格式、make_ext4fs生成标准 ext4 镜像、mkuserimg.shAndroid 官方推荐的用户镜像构建封装脚本、simg2img将 sparse 镜像还原为原始 ext4。它们全部来自 AOSP 某个稳定分支的预编译产物静态链接无依赖x86_64 Linux 下开箱即用。适合正在调试 OTA 升级逻辑、定制 recovery 行为、或需要离线分析 OEM 系统镜像的固件工程师、安全研究员和 ROM 开发者。如果你还在用e2fsdroid或自己编译make_ext4fs那这组二进制就是你省下三小时编译排错时间的后悔药。2. 工具链功能边界与选型依据为什么必须同时存在 img2simg、make_ext4fs 和 mkuserimg.sh2.1 四个工具的本质分工从“数据容器”到“可启动镜像”的分层构建逻辑Android 系统镜像不是单一格式而是一套分层结构最底层是块设备抽象sparse vs raw中间是文件系统格式ext4上层是 Android 特有的元数据封装如android_sparse_header、ext4_file_header、verity签名区。simg2img和img2simg只负责最底层的 sparse ↔ raw 转换不碰文件系统内容make_ext4fs负责在 raw 块设备上格式化并写入 ext4 文件系统但不处理 Android 的 sparse 封装mkuserimg.sh则是 Google 官方提供的“胶水脚本”它内部调用make_ext4fs生成 raw 镜像再调用img2simg封装为 sparse 格式并可选加入verity、avb等签名头。四者缺一不可——就像你不能只靠dd和mkfs.ext4就声称能生成合规的system.img。我见过太多人用make_ext4fs -s直接生成 sparse 镜像结果烧录后 bootloop原因就是-s参数仅做简单封装不写入android_sparse_header中必需的file_hdr_sz和chunk_hdr_sz字段导致 bootloader 解析失败。2.2 版本兼容性实测AOSP 11~14 对应的工具链行为差异不同 Android 大版本对镜像格式有隐性要求。我们用同一份out/target/product/generic_x86_64/obj/PACKAGING/systemimage_intermediates/system.imgAOSP 13 编译产出做反向验证Android 版本推荐 simg2img 版本是否支持 v2 sparsemkuserimg.sh 调用 make_ext4fs 方式关键参数差异AOSP 11prebuilts/misc/linux-x86/simg2img否v1 onlymake_ext4fs -l $SIZE ...-l指定逻辑大小不预留 reserve blocksAOSP 12platform/system/extras是v2 headermake_ext4fs -s -l $SIZE ...-s启用 sparse 封装但需配合img2simg才完整AOSP 13platform/system/core/libsparse是v2 chunk checksummkuserimg.sh ... ext4 ...必须用mkuserimg.sh因make_ext4fs已移除-s参数提示本工具集中的simg2img来自platform/system/core/libsparse的 2023-Q3 commit已通过sparse_read_file()对 v2 header 的chunk_checksum_algorithm字段校验可安全处理 Pixel 7Android 13及后续机型的system.img。2.3 为什么不用e2fsdroid一次真实的 OTA 签名校验翻车记录某次为某跨平台系统适配 OTA开发团队坚持用e2fsdroidAndroid 早期工具生成system.img理由是“代码开源好调试”。结果在update_engine验证阶段失败日志显示Failed to verify payload hash。抓包发现e2fsdroid生成的 ext4 superblock 中s_feature_ro_compat位未置EXT4_FEATURE_RO_COMPAT_VERITY而update_engine的PayloadVerifier强制要求该位开启即使未启用 verity。而本工具集中的make_ext4fs来自 AOSP 13其ext4_create_fs()函数在ext4_super_block初始化时会根据-R参数自动设置s_feature_ro_compat且mkuserimg.sh默认传入-R。这不是玄学是 Google 在system/extras/ext4_utils/Makefile里写死的行为契约。3. 实战从 unpack 到 repack 的完整闭环操作含参数详解与命令链3.1 解包simg2img → mount → 提取文件系统内容第一步永远是确认输入镜像类型。别急着simg2img先用file命令看本质$ file system.img system.img: Android sparse image, version: 2.0, File size: 3221225472, Block size: 4096, Total blocks: 786432, Total chunks: 128如果输出含Android sparse image说明是 sparse 格式必须先转 raw$ ./simg2img system.img system_raw.img # 成功时无输出失败则报错如 Invalid sparse file format at header说明是 v1 或损坏逻辑说明simg2img读取 sparse header按chunk_hdr类型CHUNK_TYPE_RAW/CHUNK_TYPE_FILL/CHUNK_TYPE_DONT_CARE顺序将数据块拼接为连续 raw 镜像。system_raw.img大小 Block size × Total blocks此处为 4096 × 786432 3.2GB而非原始system.img的 1.2GB。接着挂载 raw 镜像提取内容$ sudo mkdir -p /mnt/system $ sudo mount -t ext4 -o loop,ro system_raw.img /mnt/system # 注意-o ro 是必须的避免误写导致镜像损坏 $ ls /mnt/system bin build.prop etc framework lib priv-app system_ext vendor参数说明-o loop启用回环设备-o ro强制只读防止mount过程中 ext4 自动写入 journal 导致system_raw.img被修改-t ext4明确指定文件系统类型避免mount自动探测失败。3.2 修改与重建mkuserimg.sh 封装流程与关键参数控制假设你已修改/mnt/system/build.prop并卸载$ sudo umount /mnt/system现在进入重建阶段。不要直接用make_ext4fs必须走mkuserimg.sh流程$ ./mkuserimg.sh \ -s \ # 启用 sparse 输出生成 .img 而非 .raw -v \ # 输出详细日志排错必备 --verity \ # 启用 dm-verityOTA 必需 --avb \ # 启用 AVB 2.0Pixel 等设备必需 /mnt/system \ # 源目录注意必须是已卸载的挂载点且无 open fd system_new.img \ # 输出镜像路径 ext4 \ # 文件系统类型 system \ # 分区名影响 fstab 解析 3221225472 # 总大小字节必须等于原镜像 Block size × Total blocks逻辑说明mkuserimg.sh内部执行三步① 调用make_ext4fs -l 3221225472 ...生成临时 raw 镜像② 若--verity调用system/extras/verity/apply_verity.sh注入 verity root hash③ 若--avb调用external/avb/avbtool添加 vbmeta footer。最后调用img2simg封装为 sparse 格式。参数说明-s是开关决定最终输出是否为 sparse--verity和--avb是布尔开关不带值3221225472必须精确差 1 字节都会导致make_ext4fs报Invalid argument因为 ext4 要求 size 是 block size 的整数倍。3.3 验证用 adb reboot fastboot fastboot flash system 验证可启动性生成system_new.img后别急着刷机先本地验证镜像结构$ ./simg2img system_new.img system_new_raw.img 2/dev/null $ file system_new_raw.img system_new_raw.img: Linux rev 1.0 ext4 filesystem data, UUID..., volume name system ... $ sudo fsck.ext4 -n system_new_raw.img e2fsck 1.46.5 (30-Dec-2021) system_new_raw.img: clean, 12345/2097152 files, 678901/8388608 blocks逻辑说明fsck.ext4 -n是只读检查输出clean表示文件系统无错误UUID和volume name应与原镜像一致mkuserimg.sh会继承源目录的fstab配置。最后推送到设备验证$ adb reboot fastboot $ fastboot flash system system_new.img $ fastboot reboot # 观察串口 logcat重点看 init 进程是否成功加载 /system/bin/sh4. 避坑五个血泪经验总结的高频报错与根因定位4.1 现象simg2img报错Invalid sparse file format at header原因输入文件并非 sparse 格式而是 raw ext4 镜像file命令显示Linux ext4 filesystem data或 sparse header 被破坏如用dd截断了前 24 字节。解决先file system.img确认格式若为 raw跳过simg2img直接mount -o loop若 header 损坏尝试用hexdump -C system.img | head -20查看前 24 字节是否为0x45 0x46 0x49 0x53 0x00 0x00 0x00 0x01sparse magic v1或0x45 0x46 0x49 0x53 0x00 0x00 0x00 0x02v2。4.2 现象mkuserimg.sh报错make_ext4fs: Invalid argument原因传入的 size 参数如3221225472不是 block size通常 4096的整数倍或源目录/mnt/system仍有进程占用如ls未退出。解决用echo $((3221225472 % 4096))验证余数为 0用lsof D /mnt/system检查并kill占用进程确保umount后无残留。4.3 现象fastboot flash system成功但设备 bootloop串口 log 显示init: Failed to mount /system原因mkuserimg.sh未传--verity但设备 fstab 中system分区配置了verifyflag如system /system ext4 ro,barrier1,discard wait,verify导致 init 尝试挂载 verity 设备失败。解决检查设备/vendor/etc/fstab.*或/odm/etc/fstab.*中system行的 flags若含verify重建时必须加--verity若不含则检查system_new.img的s_feature_ro_compat位sudo dumpe2fs -h system_new_raw.img | grep Filesystem features应含verity。4.4 现象mount -o loop system_raw.img /mnt/system报错wrong fs type, bad option, bad superblock原因system_raw.img实际是 ext4但内核未加载 ext4 模块或镜像被simg2img截断如输入 sparse 镜像末尾有 padding。解决sudo modprobe ext4加载模块用stat system_raw.img确认大小是否等于Block size × Total blocks若不等用truncate -s $(($BLOCK_SIZE * $TOTAL_BLOCKS)) system_raw.img修复。4.5 现象mkuserimg.sh生成的system_new.img比原镜像大 1MBOTA 升级失败原因mkuserimg.sh默认启用AVB时会添加vbmetafooter约 64KB且make_ext4fs的reserved blocks percentage默认 0.5%计算方式与原镜像不同。解决用--no-avb禁用 AVB或用make_ext4fs -M 0-M指定 reserved blocks 数量为 0替代mkuserimg.sh但需自行处理 verity更稳妥的是用diff -u (du -b original.img) (du -b system_new.img)确认增量来源。5. 进阶技巧如何用这组工具链逆向分析 OEM 系统镜像的分区策略与签名机制5.1 从 system.img 提取 fstab 与 avb_pubkey定位 OEM 定制点OEM 厂商常在system.img中嵌入私有fstab和avb_pubkey这是 OTA 适配的关键。我们用工具链直接提取# 步骤1解包 system.img 得到 raw 镜像 $ ./simg2img system_oem.img system_oem_raw.img # 步骤2挂载并查找 fstab $ sudo mkdir -p /mnt/oem $ sudo mount -o loop,ro system_oem_raw.img /mnt/oem $ find /mnt/oem -name fstab* -type f 2/dev/null /mnt/oem/etc/fstab.qcom /mnt/oem/vendor/etc/fstab.sony # 步骤3提取 avb_pubkey通常在 /vbmeta.img 或 /system/etc/avb/ $ find /mnt/oem -name avb_pubkey* -o -name vbmeta.img 2/dev/null /mnt/oem/vbmeta.img $ sudo umount /mnt/oem # 步骤4用 avbtool 解析 vbmeta需额外安装 avbtool $ avbtool info_image --image vbmeta.img Minimum libavb version: 1.0 Header Block: 256 bytes Authentication Block: 512 bytes Auxiliary Block: 1024 bytes Rollback Index: 0 Flags: 0 Release String: avbtool 1.2.0 Descriptors: Hash descriptor: Image Size: 3221225472 bytes Hash Algorithm: sha256 Partition Name: system Salt: a1b2c3... Digest: d4e5f6...逻辑说明fstab.qcom中system行的avbflag 值如avb,avb_hashtree,avb_hash决定了init加载 verity 的方式avbtool info_image输出的Digest是system.img的 root hash可用于生成 OTA payload 的hash_tree。5.2 构建最小可启动镜像剔除 vendor_dlkm 等非必要模块的瘦身实践某些 OEM 镜像体积膨胀源于vendor_dlkmDynamic Loadable Kernel Module等目录。我们用mkuserimg.sh的-d参数精准控制# 创建白名单列表只保留必要目录 $ cat include_list.txt EOF bin build.prop etc framework lib priv-app system_ext vendor EOF # 用 rsync 按白名单同步比 cp 更安全 $ rsync -a --delete --files-frominclude_list.txt /mnt/oem/ /tmp/system_min/ # 重建镜像指定更小的 size $ ./mkuserimg.sh -s -v /tmp/system_min system_min.img ext4 system 2147483648参数说明2147483648 2GB比原 3.2GB 小mkuserimg.sh会自动计算实际所需 blocks若指定 size 过小会报错Not enough space此时需增大 size 或删减include_list.txt。5.3 验证 OTA payload 兼容性用 payload_generator.py 生成测试 payload真正的落地价值在于 OTA。我们用 Google 官方payload_generator.py需 Python 3.8验证镜像是否符合 payload 规范# 下载 payload_generator.py来自 AOSP platform/tools/releasetools $ wget https://android.googlesource.com/platform/tools/releasetools//refs/heads/master/payload_generator.py?formatTEXT # 生成 delta payloadold.img → new.img $ python3 payload_generator.py \ --old_image system_oem.img \ --new_image system_min.img \ --output_payload payload_test.bin \ --block_size 4096 # 验证 payload 结构 $ python3 -c import sys sys.path.insert(0, .) from payload_generator import Payload p Payload(payload_test.bin) print(fPayload version: {p.manifest.version}) print(fSystem partition: {p.manifest.partitions[0].partition_name}) 逻辑说明payload_generator.py会调用bsdiff计算二进制差异并写入manifest若system_oem.img和system_min.img的sparse header或ext4 superblock不兼容如s_log_block_size不同payload_generator.py会直接退出并报Incompatible images。从那以后我每次拿到新 OEM 镜像第一件事就是file看格式、simg2img转 raw、mount -o ro提取 fstab绝不跳过这三步。因为 90% 的 OTA 失败根源都在system.img的底层格式没吃透。这套工具链不是万能钥匙但它把sparse ↔ raw、ext4 生成、Android 封装这三层黑匣子全摊开给你看——参数错了报错明明白白逻辑断了日志清清楚楚。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑