system.img解包修改与重打包实战:Android镜像定制完整指南
2026/9/21 16:29:56 网站建设 项目流程

最近好几个朋友都在折腾第三方ROM包时卡在system.img这一步,跑来问我能不能写一篇能落地的教程。说实话,这玩意儿初次接触确实劝退,命令看着吓人,还动不动就在打包环节翻车。但拆过几次之后你会发现,它本质上就是一份可以整体挂载的Linux文件系统,解压和修改本身并不难,难点全在于“改完还能刷回去正常开机”。这篇教程我会把Windows和Linux两条路线一次性讲透,从镜像格式识别、解压挂载、文件修改,到重新打包、刷回设备,每一步都按实战记录来写,中间穿插我踩过的坑和排查思路。想自己精简系统应用、改开机动画、研究系统内部结构的同学,这篇可以直接照着操作。

1. 拆system.img前,先搞清楚你面对的是个什么文件

1.1 system.img到底是干什么用的

Android设备内部存储会被划分成多个分区,每个分区各管一摊事情。system分区就是存放操作系统主躯体的地方,包括Android框架层代码、系统应用、核心库文件、字体、系统铃声、权限配置等。system.img就是整个/system目录的完整镜像文件,相当于把一台服务器的系统盘整体打包成了一个文件。刷机时,fastboot flash system system.img就是把这个镜像原样写入设备的system分区。

可以把它理解成一个特殊格式的压缩包,但它不像zip那样随便就能解开,因为它内部是一个完整的Linux文件系统,默认是ext4格式,新设备上越来越多地采用erofs等只读文件系统。它里面的权限、属主、SELinux安全上下文信息都极其敏感,改错一个字段,轻则某个应用闪退,重则直接开不了机。

网上下载的第三方ROM包(zip格式)解开之后,你会发现里面有system.imgboot.imgvendor.img等一堆镜像文件。boot.img管内核和启动流程,vendor.img管硬件厂商相关代码,而我们常说的“精简系统”“去掉预装应用”“改默认桌面”,绝大多数要动的地方都在system.img里。

1.2 什么情况下你才会想起去改它

日常使用中你基本不会碰system.img,因为它属于只读分区,普通用户没有写入权限。但遇到下面这些需求,你就不得不把它掏出来:

  • 精简系统:去掉运营商预装应用、厂商全家桶,这些应用很多存在system/appsystem/priv-app目录下。
  • 修改系统级配置:比如改build.prop里的型号名称、DPI密度、默认时区、开机动画里的bootanimation.zip
  • 替换系统应用:把某个系统应用换成同样包名的修改版,或者往priv-app里塞需要系统权限的工具。
  • 移植和逆向研究:研究某款系统的内置功能、从别的ROM里提取某个应用或库文件放进当前系统。
  • 学习文件系统结构:想彻底搞明白Android系统启动后加载了哪些东西。

需要注意的是,现在很多新手机对system分区有完整性校验(Android Verified Boot,简称AVB),系统启动时会验证镜像的数字签名。如果你的设备bootloader已经解锁,通常可以通过fastboot命令附带--disable-verity --disable-verification参数关闭校验,或者直接使用userdebug版本的固件,否则就算你成功修改了镜像,刷进去也大概率卡在开机界面。这部分后面我会专门说。

2. 不同镜像格式决定解压工具:先识别再动手

2.1 三种主流格式的识别方法

很多教程一上来就教你挂载,但忽略了一个前提:你手里的system.img到底是什么格式?不同格式用的工具完全不同,强行操作只会浪费一晚上时间。

最常见的是下面三种:

格式特点常见场景
raw ext4最原始的ext4文件系统镜像,结构完整老设备、部分卡刷包解包后的镜像
sparse ext4带sparse稀疏头部的ext4镜像,文件大小更小官方ROM刷机包最常见
erofs只读压缩文件系统,读取性能好Android 10以后越来越多新设备采用

在Linux终端里,用一条file命令就能识别:

file system.img

输出大致会是这样:

  • Android sparse image, version: 1.0说明是sparse格式。
  • Linux rev 1.0 ext4 filesystem data, UUID=...说明是raw ext4格式。
  • erofs filesystem说明是erofs格式。

Windows下没有file命令,但你可以用Notepad++或任何十六进制编辑器打开文件头部看magic字节。ext4的magic是53 ef,erofs的magic是e0 f5 81 76,sparse的magic是3a ff 26 ed。不过说实话,逐个看十六进制太麻烦了,我更建议Windows用户装一个WSL,进去直接执行file命令,一下就能判断。

2.2 为什么格式判断这么重要

因为raw ext4可以直接挂载或解包,sparse需要先转换成raw才能操作,而erofs用的又是一套完全不同的工具链。如果你把sparse格式直接丢给挂载命令,内核会报错找不到文件系统;如果你把erofs格式当成ext4去挂载,同样会失败。

我一开始折腾的时候不知道还有sparse这回事,拿一个sparse镜像反复执行mount命令,系统一直提示wrong fs type,我还以为是镜像文件损坏了,重新下载了三遍。后来才明白,先做格式识别,然后simg2img转成raw,一分钟就搞定了。

实际上,官方ROM包里的system.img基本都是sparse格式,因为Google和厂商希望尽量减少刷机包体积。而第三方作者做的精简包,有些会直接使用raw格式方便用户修改。所以拿到镜像文件后第一件事永远是file system.img,不要跳过。

3. Linux平台实操:挂载修改的完整流程

3.1 搭建Linux侧解压环境

如果你本来就是Linux用户,这一步最简单。以Ubuntu/Debian为例,主要需要这几样工具:

sudo apt update sudo apt install -y simg2img e2fsprogs erofs-utils
  • simg2img:将sparse镜像转换成raw镜像。
  • e2fsprogs:提供mountfsckdebugfs等ext4文件系统工具。
  • erofs-utils:提供fsck.erofsdump.erofs等erofs工具。

有的发行版包名可能不太一样,比如simg2img在部分老仓库里叫android-tools-fsutils。如果安装时提示找不到包,可以用apt search simg2imgapt search sparse搜一下。

如果机器是Arch系,用pacman装对应包即可。无论哪个发行版,核心原理都一样:先把sparse转raw,然后挂载到某个目录,像操作普通文件夹一样操作里面的文件。

3.2 识别、转换并挂载system.img

第一步是识别格式,第二步是转换(如果是sparse),第三步是挂载。

# 1. 查看文件类型 file system.img # 2. 如果是sparse sparse image,转换成raw simg2img system.img system.raw.img file system.raw.img # 确认转换成功 # 3. 挂载raw镜像到目录 sudo mkdir -p /mnt/system sudo mount -o loop system.raw.img /mnt/system # 4. 查看结果 ls /mnt/system

关键点在于mount -o loop里的loop参数,它告诉内核把这个普通文件当作块设备来处理。成功挂载后,/mnt/system里就会看到熟悉的apppriv-appframeworkbuild.prop等目录和文件。

修改完文件后,卸载时记得先确保没有进程占用目录,否则会提示target is busy

sudo umount /mnt/system

如果提示busy,用lsof /mnt/system看看是哪个进程占用了,关掉后再卸载。卸载之后最好跑一遍文件系统检查:

e2fsck -f system.raw.img

这一步能发现你在修改过程中有没有搞坏文件系统结构,如果报错,建议重新从原始镜像开始,不要带着错误继续打包。

3.3 修改文件时最容易忽略的权限与上下文问题

镜像挂载后,你会发现自己用普通用户身份访问时提示权限不足,因为Android镜像里的文件属主都是root,权限也设置了限制。这时候用sudo操作就行:

sudo rm -rf /mnt/system/app/SomeBloatware sudo cp /path/to/SystemApp.apk /mnt/system/priv-app/

但这里藏着两个大坑,新手十有八九都会栽进去。

第一个坑是文件权限。你从桌面环境复制进去的文件,权限往往继承自你当前的umask,比如644甚至666,但Android系统应用目录里的文件通常有严格的权限要求。比如priv-app目录权限一般是0755,应用文件权限一般要求0644,可执行文件要求0755。如果你复制的文件权限不对,系统启动时应用会被拒绝加载,或者直接导致SystemServer崩溃。

第二个坑是SELinux上下文。Android系统的SELinux策略非常严格,每个文件都有自己的安全上下文标签,比如系统应用的文件应该是u:object_r:system_file:s0,可执行文件可能是u:object_r:system_file:s0或更具体的类型。你新复制进去的文件默认上下文很可能完全不对,刷机后就会触发avc: denied日志,系统表现是各种诡异——应用闪退、服务起不来、设置界面空白。这时候再把镜像挂载回来,用ls -Z查看文件上下文,发现和周围的文件完全不同,就知道问题出在哪了。

正确做法是在修改文件时保留原有的属主、权限和SELinux上下文:

# 先查看原文件的属主、权限、上下文 ls -lZ /mnt/system/priv-app/SystemApp/SystemApp.apk # 复制新文件后,手动调整 sudo chown root:root /mnt/system/priv-app/NewApp/NewApp.apk sudo chmod 0755 /mnt/system/priv-app/NewApp/ sudo chmod 0644 /mnt/system/priv-app/NewApp/NewApp.apk sudo chcon -u system_u -r object_r -t system_file /mnt/system/priv-app/NewApp/NewApp.apk

如果是替换已有的应用,最好的办法是保留原应用的文件权限和上下文不变,直接把新APK内容覆盖进去。更多情况下,重新打包时会用file_contexts文件来自动设置上下文,这个我在第5节展开讲。

4. Windows平台实操:WSL挂载与纯Windows工具

4.1 为什么不推荐直接在Windows上用7-Zip解压

很多Windows用户第一反应是用7-Zip直接打开system.img,以为像打开zip一样方便。实际上,7-Zip对ext4镜像的支持非常有限,虽然能列出部分文件结构,但会遇到这些问题:

  • 文件权限、属主信息丢失,根本没地方显示。
  • 部分ext4特性(如UUID、扩展属性、SELinux上下文)无法处理。
  • 只能解压提取,不能修改后重新生成合法的镜像文件。
  • 遇到sparse格式或erofs格式时基本无能为力。

所以,7-Zip只适合你“看一眼”镜像里有什么文件,不适合做完整解包和重新打包。真要在Windows上完成“解压→修改→重打包”这个闭环,我推荐下面两条路。

4.2 方案一:WSL里完成整条修改链

WSL(Windows Subsystem for Linux)是微软官方的Windows子系统,你不需要装虚拟机或者物理Linux环境,直接在Windows里跑一个Ubuntu终端,然后Linux能干的活儿它基本都能干。

安装完WSL后,把system.img放到Windows的某个盘符里,比如D:\rom\system.img,然后进入WSL终端,访问Windows盘符上的文件:

cd /mnt/d/rom file system.img

如果遇到权限问题,或者WSL跨文件系统操作太慢,更好的做法是把镜像复制到WSL的Linux文件系统里:

cp /mnt/d/rom/system.img ~/rom/ cd ~/rom/

然后按照第3节的步骤执行simg2imgmountumount就行。修改完的镜像再复制回Windows盘:

cp ~/rom/system_new.img /mnt/d/rom/

WSL方案最舒服的地方在于,你不用额外装任何Windows专用软件,所有Linux工具都能直接用。而且WSL里跑的是真正的Linux内核,挂载ext4、erofs都没有兼容性问题。装WSL2以后性能也足够,处理大镜像文件不会卡到怀疑人生。

4.3 方案二:用第三方驱动把ext4镜像变成Windows盘符

不想用WSL的话,Windows上也有专门处理Linux文件系统的工具。早期比较流行的是ext2explore,但它只能读取,不能写入,改不了文件。后来像我实际用过比较稳的是Paragon公司的Linux File Systems for Windows,装上以后Windows资源管理器里能直接挂载ext4镜像,把镜像变成一个虚拟盘符,读写都没问题。类似的工具还有DiskInternals Linux Reader,但那个偏读取查看,写入支持不稳定。

这类工具的优点是对Windows用户友好,鼠标点一点就能操作文件。但缺点也很明显:一是很多工具是付费的,免费版功能受限;二是它们只解决“读写ext4”的问题,不解决“重新打包img”的后续步骤。你改完文件之后,还是需要某种方式把整个目录重新制作成镜像,这通常还是得回到Linux环境去执行make_ext4fsmke2fs命令,否则只能把修改过文件的raw镜像直接保存。所以我个人还是强烈推荐WSL路线——与其装一堆半吊子的图形工具,不如一步到位用WSL闭环解决。

4.4 从Windows里识别镜像格式

在Windows上执行file命令不方便,但如果你装好了WSL,这个问题自然就解决了。进入WSL后执行:

file system.img

如果你还没装WSL,临时用7-Zip打开镜像,看7-Zip能不能识别文件系统结构,或者用十六进制工具查看文件头部的magic字节,也能有一个初步判断。不过准确率最高的还是file命令,因为它会完整解析文件头部信息并匹配既有格式库。

5. 重新打包:把改完的目录变回可刷入的system.img

5.1 打包工具怎么选

很多人解压修改完,卡在最后一步不知道怎么把目录重新做成镜像。打包工具的选择取决于你原始镜像的格式:

  • ext4镜像:用make_ext4fs或者更标准的mke2fs+e2fsdroid
  • erofs镜像:用mkfs.erofs
  • sparse格式:打包成完整raw镜像后,再用img2simg转成sparse,或者打包时直接加sparse参数。

make_ext4fs是老牌工具,在Android 4.x到8.x时代非常流行,一条命令就能把目录打包成ext4镜像,适合快速实验。但它对SELinux上下文处理得不够完善,新版Android系统镜像里如果缺少正确的file_contexts,刷进去很容易出问题。

更标准的方式是使用AOSP工具链里的mke2fs+e2fsdroidmke2fs负责创建空的ext4文件系统,e2fsdroid负责把目录内容写进镜像,并在写的过程中根据file_contexts文件设置每个文件的安全上下文。这个方案在Android 9以上已经成了官方默认做法。

5.2 ext4镜像的重新打包过程

先用最简单的make_ext4fs法说明思路。假设你已经把修改后的目录放到了/mnt/system_new,现在要生成新的镜像文件:

make_ext4fs -s -l 512M -a system system_new.img /mnt/system_new

参数含义:

  • -s:生成sparse格式镜像。如果你的设备能接受raw格式,可以去掉这个参数。
  • -l 512M:指定分区大小。这里必须和你原始system分区大小一致或者略小。如果设置得比原始分区大不少,刷入时可能超出分区实际容量。
  • -a system:指定挂载点,同时让工具在打包时按Android的挂载规范设置文件路径。

如果使用mke2fs+e2fsdroid的组合,命令会长一些,但更标准:

# 1. 创建一个空的ext4镜像文件 # 512M 是对应分区大小 mke2fs -t ext4 -L system -b 4096 -I 256 -O has_journal system_new.ext4.img 512M # 2. 把目录内容写入镜像,并设置SELinux上下文 e2fsdroid -f /mnt/system_new -a /system -S file_contexts system_new.ext4.img

file_contexts文件通常可以从原ROM包中提取,或者从AOSP源码的system/sepolicy目录里找到。如果你手头没有这个文件,也可以用原镜像挂载后根据ls -Z导出的信息手工整理一个,但这个工作量比较大,适合对SELinux机制很清楚的人。

最终生成system_new.ext4.img后,如果原始镜像本身是sparse格式,再用img2simg转换:

img2simg system_new.ext4.img system_new_sparse.img

5.3 erofs镜像的打包示例

如果你的设备比较新,原始system.img是erofs格式,打包工具是mkfs.erofs。erofs的设计目标就是只读文件系统,所以打包流程和ext4思路完全不同,它不需要走“挂载目录→写入文件→设置上下文”的流程,而是直接把指定目录编译成一个压缩只读镜像:

mkfs.erofs -zlz4hc system_new.img /mnt/system_new

常用参数:

  • -z lz4hc:指定压缩算法,erofs常见压缩算法有lz4、lz4hc,后者压缩率更高。
  • -E uuid=...:可以指定UUID,但一般不需要。
  • -V:显示版本信息。

erofs镜像不能像ext4那样随意挂载修改后重新打包,因为文件系统的设计初衷就是只读,而且它的元数据存储方式更紧凑。修改时通常需要先用fsck.erofsdump.erofs解析,但这方面工具少很多。如果对erofs不熟,我会建议优先考虑用安卓解包工具把erofs镜像先转成ext4或者直接解出文件系统目录,修改后再用erofs打包,或者干脆在打包前把分区格式转成ext4(前提是设备内核支持)。

5.4 打包后验证与刷回设备

打包完成不等于万事大吉,我强烈建议你先验证再刷机,否则很容易白忙活一场。验证分四步:

  1. 确认新镜像文件类型正确:file system_new.img
  2. 挂载新镜像检查内容:sudo mount -o loop system_new.img /mnt/system_check,进去看一下文件数量、关键文件是否存在、修改是否生效。
  3. 卸载后跑一遍文件系统检查:e2fsck -f system_new.img,如果报错就要重新打包。
  4. 有条件的话,用一个支持动态分区解析的模拟器或twrp里mount试试,确认能正常识别。

刷回设备的命令是:

fastboot flash system system_new.img

如果设备启用了AVB校验,可能还需要同时刷入关闭校验的vbmeta:

fastboot flash vbmeta vbmeta.img --disable-verity --disable-verification

注意,这条命令会关闭系统的verity校验,意味着设备的安全性有一定下降。在这个前提下,修改后的系统才更容易启动。

还有一条常识性提醒:刷机前一定要备份当前系统,尤其是Data分区里的照片、聊天记录、应用数据。system分区被刷后是没法直接回滚到原状态的,除非你留着原始镜像并重新刷回。我个人的习惯是把原始system.img先复制一份到电脑单独存放,改坏了还能随时刷回去。

6. 高频踩坑记录与排查思路

6.1 常见问题速查表

下面这个表格是我折腾过程中遇到最多的几类问题,以及对应的排查和解决思路:

症状可能原因解决办法
mount提示wrong fs type镜像可能是sparse格式或erofs格式先执行file识别格式,sparse转raw;erofs用专用工具处理
修改后刷机卡第一屏SELinux上下文丢失或AVB校验失败file_contexts重新打包;关闭verity;检查vbmeta
系统应用闪退应用权限不对或依赖缺失检查APK权限是否为0644、目录是否为0755;确认所需lib已放入对应目录
分区空间不够,打包失败修改后内容超出了原system分区大小删掉更多无用应用;减小打包镜像的-l分区大小
打包后刷入提示size too large镜像实际大小超过设备分区确认-l参数指定的分区大小;不要超过原始分区容量
卸载目录时报target is busy有进程正在访问挂载目录lsoffuser找到占用进程并关闭
无法用普通用户访问挂载目录ext4镜像里的文件属主是root使用sudo操作,或者在挂载时加-o uid=你的用户临时改变默认属主
Windows下用7-Zip打开但看不到完整文件spase/ext4特有结构不支持不要依赖7-Zip,用WSL挂载或专用Linux文件系统工具

6.2 几条能救命的实战经验

第一,尽量使用同一个工具链完成解压和打包。早期精简单system的时候,我用Linux挂载解压,然后拿到Windows上用工具打包,折腾了三天,各种启动崩溃,后来发现是两套工具对文件属性的理解不一致,导致部分文件的归属地和SELinux标签被修改了。同一套工具链(比如全部用AOSP工具)能最大程度减少这类问题。

第二,修改system.img的时候,尽量用“复制出一个新目录再修改”的思路,不要直接在挂载后的原镜像上操作。比如先cp -a把挂载目录整个复制出来,然后在副本上改,改完再打包。这样就算打包失败,原始镜像还是完好的,还能从头再来。

第三,如果修改完后系统能在Recovery模式下正常启动,但在正常启动时卡logo,优先怀疑SELinux上下文问题。进Recovery挂载system分区,用ls -Z对比几个系统应用文件的上下文,发现不对就重新从原镜像提取正确的file_contexts,再打包一次。大多数莫名其妙的启动问题都能通过这一步解决。

第四,对于不熟悉的设备,不要贪快直接刷入新镜像。先用fastboot boot而不是fastboot flash测试:把新镜像临时加载到内存启动,不写入分区。不过这个功能不是所有设备都支持,支持的设备上非常管用,安全系数高很多。

第五,erofs格式的设备虽然打包比较麻烦,但你仍然可以先用simg2img把sparse erofs镜像转成raw erofs镜像,然后用erofs工具挂载或解包;如果工具不顺手,就把镜像丢给fsck.erofs --extract=目录这种方式提取文件,修改后再整体打包。原理上都绕不开“解出文件目录→修改→重新编译成镜像”这三步,工具差异只是路径不同。

最后再分享一个小技巧。我实际操作中习惯把整套解包、修改、打包的常用命令写成一个小的shell脚本,每次拿到新ROM包就自动帮我完成格式识别、sparse转换、挂载目录创建这几个重复动作。毕竟这活儿偶尔才做一次,命令记不全很正常,脚本化之后就能稳定复现,不用每次重新翻教程。

如果你只是想删几个系统应用,不考虑这么深的原理,直接用magisk模块配合系统less模式也能做到类似效果,但想彻底掌控system分区,学会手动处理system.img依然是绕不开的一课。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询