system.img修改全攻略:格式识别、解包重打包与刷写避坑指南
2026/9/21 17:07:47 网站建设 项目流程

1. system.img为何要改:先搞清楚这张"系统盘"的脾气

玩Android的时间稍微长一点,基本都会遇到这个需求:自带应用删不掉、想加个开机脚本、想把某几个系统应用替换成自己改过的版本、或者单纯想把谷歌全家桶从国行固件里拔掉。这些操作的最终落点,几乎都是那个又爱又恨的system.img

很多新手第一次接触system.img,容易把它当成普通的"镜像文件",以为像解压zip一样双击就能打开。结果在Windows上试了半天,发现7-Zip打不开、WinRAR也不认识,于是开始怀疑文件是不是坏了。这不是你的问题,是system.img的封装方式跟普通压缩包压根不在一个维度。

先说清楚system.img到底是什么。它是Android系统分区(system分区)的完整磁盘镜像,挂载到设备后的路径是/system,里面装着Android运行的核心东西:系统框架(framework)、预装应用(/system/app、/system/priv-app)、原生库(/system/lib、/system/lib64)、可执行文件(/system/bin)、系统配置(/system/etc),以及build.prop这个系统属性文件。可以说,手机开机能跑起来,全靠这个分区。

它的"脾气"在于:这个镜像不是普通的文件打包格式,而是一个包含了文件系统结构的块设备镜像。我们看到的system.img,本质上是把整个system分区按块(block)逐字节复刻出来的文件。所以要在电脑上修改它,核心思路不是"解压文件",而是"把文件系统挂载起来,改完再固化回去"。

这篇文章讲的操作,面向的场景是:你手里有一个system.img(可能是从ROM包解出来的,也可能是从手机里备份出来的),想在Windows或Linux电脑上打开它、往里面塞东西或者删东西、然后重新打包成可用的镜像。这个流程在定制ROM、系统精简、功能移植、学习Android系统结构时都会反复用到,属于玩机基本功里比较硬核的一项。

2. 识别镜像格式:raw、sparse与erofs的分辨方法

拿到一个system.img,第一件事不是着急找工具,而是先判断它是什么格式。格式判断错了,后面全部白干。这一步花不了30秒,但能帮你避开接下来一小时的无效操作。

2.1 三种最常见的system.img格式

raw ext4镜像这是最"规矩"的格式。整个镜像就是一份完整的ext4文件系统镜像,文件系统头部(superblock)在镜像文件的最开头,偏移量是0。这种镜像最老实,mount命令直接就能挂载,不需要任何转换。Google官方的出厂镜像(Factory Image)里,如果解出来是system.img,很多就是raw ext4,或者带sparse属性的raw ext4。

sparse镜像Android为了减少固件体积和刷写时的传输量,搞出了一种"稀疏镜像"格式。它的原理是:文件系统中大量未使用的块不占实际存储空间,用一个描述头(sparse header)配合chunk记录哪些区域有真实数据、哪些区域是空洞。好处是镜像文件体积小很多,坏处是它不是一个标准的文件系统镜像,没法直接挂载,必须先用工具转换成raw格式。手机ROM里解出来的system.img,大部分是这种sparse镜像。

erofs镜像这个稍微新一点。erofs(Enhanced Read-Only File System)是Linux内核4.19起引入的只读文件系统,专门为嵌入式场景设计。近几年的手机厂商(尤其是国内厂商)为了提升随机读取性能和节省存储空间,越来越多地把system分区格式从ext4换成了erofs。erofs镜像在文件头有固定的magic number,跟ext4很好区分。对erofs镜像的操作,不能用ext4的工具链,得用erofs-utils这套工具。

2.2 一分钟判断格式的方法

Linux下用file命令就够了,Windows下可以用HxD这类十六进制编辑器看文件头。我整理了一个速查表:

文件头特征格式处理思路
偏移0x438处有\x53\xEFext4(raw)直接挂载
文件头有3A FF 26 ED,且前几字节有SPARSE字样(ASCII)sparse先转raw再处理
文件头有\xE2\xE1\xF5\xE0(erofs magic)erofs用erofs-utils处理

Windows下没有file命令的话,用HxD打开文件,看最前面16个字节就好。如果是sparse格式,你能很直观地看到文件头有字符串SPARSE;如果是ext4,文件头的\x53\xEF这一对字节非常显眼;erofs的magic则是一串不规则的字节E2 E1 F5 E0

2.3 为什么格式判断如此关键

我见过不少人在这一步翻车。拿着一份erofs镜像,按照网上的老教程用simg2img转稀疏,又用debugfs去挂载,结果报错报得莫名其妙。还有人把sparse镜像直接拖到Linux虚拟机里mount -o loop,内核告诉他不认识这个文件系统。这些问题的根源只有一个:格式没摸清就开始操作。

提示:rom包里的system.img如果要刷入设备,厂商可能有额外的校验机制(AVB、dm-verity等)。这类校验在修改镜像后会触发,导致设备无法开机或反复重启。这个问题在第5节专门讲,这里先有个印象就行。

3. Linux下解包与修改:一条龙操作实录

Linux是这个活儿的主战场。几乎所有处理system.img的工具都是Linux原生的,操作链路最顺,踩坑最少。如果你手里只有Windows电脑,也别急着关页面——第4节会讲Windows的具体玩法。

3.1 工具准备与安装

需要的东西不多,但都是关键角色:

  • simg2img:sparse转raw的工具,Android官方源码里自带,发行版软件源里可能叫android-tools-fsutils或类似名字。
  • mount命令:Linux自带的挂载工具,需要root权限。
  • debugfs:ext4文件系统调试神器,e2fsprogs包的一部分。
  • make_ext4fsmkfs.ext4:重新打包ext4镜像时用。
  • erofs-utils:处理erofs镜像的官方工具集,包括fsck.erofsdump.erofsmkfs.erofs

Debian/Ubuntu系直接一条命令解决:

sudo apt install android-tools-fsutils e2fsprogs erofs-utils

其他发行版类似,Fedora系是dnf install android-tools erofs-utils。如果包里找不到simg2img,可以直接用Android官方源码编,但大多数场景下发行版仓库里的够用了。

3.2 第一步:sparse转raw(如果是sparse格式)

先用file system.img看格式。如果确认是sparse,执行转换:

simg2img system.img system_raw.img

转换完成后,可以用file system_raw.img确认一下,这次应该能看到Linux rev 1.0 ext4 filesystem data之类的描述。转换的原理很简单:simg2img会解析sparse header里的chunk信息,把稀疏的数据块展开成连续的raw镜像。这个过程中文件体积会明显变大,是正常现象。

3.3 第二步:挂载system.img

挂载是读取和修改ext4镜像最直接的方式。先在本地建一个目录当作挂载点:

mkdir -p /mnt/system sudo mount -o loop system_raw.img /mnt/system

看到这你可能想问:为什么要加loop?因为system.img是一个普通文件,不是真正的块设备。loop参数会让内核通过loop设备把这文件模拟成一块磁盘,然后才能按文件系统来挂载。这一步是理解整个流程的关键。

挂载成功后,/mnt/system下就是完整的Android系统目录树。你能看到apppriv-appbinetcframework这些熟悉的目录。到这一步,修改就成了普通的文件操作:

# 删除一个预装应用 sudo rm -rf /mnt/system/app/SomeBloatware # 往系统里塞一个自己的脚本 sudo cp my_script.sh /mnt/system/bin/ sudo chmod 755 /mnt/system/bin/my_script.sh

如果只想查看、不想修改,也可以只读挂载:

sudo mount -o loop,ro system_raw.img /mnt/system

3.4 第三步:取消挂载与检查

改完后务必要正确卸载:

sudo umount /mnt/system

为什么"务必要"?因为你在挂载状态下对镜像做的任何修改,实际上是写在内存里的页缓存中,并没有真正落盘。只有umount才会把缓存里的脏页刷回到镜像文件。直接拔电源、直接删挂载目录、或者系统崩溃,都会导致修改丢失,甚至损坏镜像。

umount之后,建议跑一遍文件系统检查:

e2fsck -f system_raw.img

这个检查会扫一遍ext4文件系统的完整性。如果上一轮操作中某个文件写到一半出了问题,这里能发现并修复。检查完再进入打包环节。

3.5 第四步:重新打包成sparse(按需)

如果你只想得到raw格式的system.img来直接fastboot刷写,那到3.4就够了。但如果你想把它塞回一个zip格式的ROM包里保持体积优势,就需要把raw转回sparse。工具是img2simg

img2simg system_raw.img system_new_sparse.img

这一步是可选的,取决于你的使用场景。fastboot刷写一般两种格式都认,但Recovery卡刷包里的system镜像基本都要sparse格式。

3.6 erofs镜像的特殊处理

如果第2节判断格式是erofs,整个流程要换成另一套工具。erofs的关键特征是只读,你不能像ext4那样直接挂载然后写文件。官方提供的是fsck.erofs(检测)和dump.erofs(查看),但修改erofs镜像的常规做法是:先解包成文件树,改完文件树,再用mkfs.erofs重新打包。

# 解包(需要erofs-utils,部分发行版包名是erofs-utils) fsck.erofs --extract=/mnt/erofs_extract system.img # ...修改 /mnt/erofs_extract 下的文件... # 重新打包 mkfs.erofs -zlz4hc system_new.img /mnt/erofs_extract

注意mkfs.erofs的压缩算法参数(-z)和原始镜像可能不一样。同样一份文件,用不同压缩算法打包,体积和读取性能会有差异。建议先用dump.erofs system.img看看原镜像用了什么算法,尽量保持一致,避免刷入后出现意外问题。

经验:我处理过的绝大多数国内厂商固件,近几年已经从ext4切到了erofs。遇到新ROM包,先按第2节的方法判断格式,别默认它是ext4,这是最省时间的习惯。

4. Windows平台的三种路径:从原生工具到WSL

Windows下改system.img确实比Linux麻烦不少,但也不是无路可走。我把实际验证过可行的路径整理成三条,按推荐度排序,你可以根据自己的需求选。

4.1 路径一(强烈推荐):WSL,把Windows变成Linux工作台

如果你装了WSL(Windows Subsystem for Linux),那恭喜你,Windows下的操作体验几乎和Linux完全一致。WSL不仅仅是"在Windows里跑个Linux终端",它是完整的Linux内核在微软的虚拟化平台上运行(WSL2),可以直接挂载loop设备。

具体操作逻辑是:在Windows文件系统里放好system.img,然后在WSL里访问它。WSL会自动把Windows的盘挂载到/mnt/c/mnt/d这样路径下。比如你把镜像放在D:\rom\system.img,在WSL里访问路径就是:

cd /mnt/d/rom file system.img

唯一的注意事项是性能。从WSL访问/mnt/d这类跨文件系统的路径,I/O速度会比WSL内部文件系统慢不少。处理几个GB的system.img时,转换sparse格式会等得久一点,但完全在可接受范围内。如果频繁处理镜像,可以把文件拷贝到WSL的home目录下操作,速度会快很多:

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

WSL里安装工具链和Linux环境完全一样,第3节的所有命令都能用。这是目前Windows平台处理镜像最省心的方案,没有之一。

提示:WSL2默认支持loop设备吗?我在WSL2上实测,mount loop是可以用的,但如果遇到权限问题,试试在管理员权限的PowerShell里执行wsl --shutdown后重开WSL,或者检查/etc/wsl.conf[automount]的配置。

4.2 路径二:纯Windows原生工具,适合只做简单操作

如果你不想装WSL,只想快速从system.img里提取几个文件,试试ext2explore这个老牌工具。它是Windows下直接读取ext4文件系统的图形化工具,支持raw ext4镜像的直接浏览和文件导出。打开后选"File -> Open",指向system.img,就能像资源管理器一样浏览系统目录了。

但注意,ext2explore只支持读取,不支持写入。它解决的是"我想看看system.img里有什么、把某个应用提取出来"这类需求。如果你想删除应用、修改配置,这个工具无能为力。

另一个思路是用DiskGenius的"打开镜像文件"功能。它对新版ext4的支持比ext2explore好一些,但同样主要面向文件提取场景,写回能力有限。

第三个工具是OSFMount。它能把raw ext4镜像挂载成一个Windows盘符。挂载后Windows的explorer能看到盘符,但Windows本身不原生支持ext4文件系统,所以OSFMount实际上只是把镜像关联到了驱动层,真正读取还是需要搭配ext4驱动。整体来说,这条路配置繁琐、兼容性一般,不如WSL来得干净。

4.3 路径三:虚拟机兜底,没别的办法时的选择

如果WSL装不上、工具又不够用,就上虚拟机。在VMware或VirtualBox里装一个Ubuntu Server(不带图形界面,纯命令行,资源占用小),然后把system.img通过共享文件夹或直接拖拽拷进虚拟机。后面的操作就完全变成Linux流程了。

虚拟机的缺点很明显:占内存、启动慢、共享文件夹的传输速度让人着急。但它的优势是环境干净、和物理机隔离,不用担心搞坏Windows。如果你手头正好有一台常开的Linux虚拟机,那这条路其实比装WSL还省事。

4.4 Windows下格式判断:没有file命令的替代方案

Windows下没有Linux的file命令,判断镜像格式有两个办法:

  1. 用HxD打开镜像,看文件头十六进制:sparse格式能看到ASCII的SPARSE字样,ext4格式在偏移0x438处有\x53\xEF
  2. 用WSL里的file命令(如果有WSL的话)。

提前判断格式能帮你决定后续用哪套工具链,千万别跳过。

5. 重新打包与刷写:让改动真正落到手机上

在电脑上改完system.img,只是完成了前半程。后半程是把镜像弄回手机里,并让它能正常开机。这一节讲打包时容易忽略的关键参数,以及刷写后常见的"开机死循环"问题。

5.1 重新打包时最关键的参数:分区大小

make_ext4fs打包时,最核心的参数是镜像的"目标大小"(size)。这个大小必须和你设备真实system分区大小匹配。如果打包出来的镜像比分区大,刷写会失败;如果比分区小太多,文件系统可能用不满,浪费空间,某些设备还会因为分区表检查不通过而报错。

怎么拿到真实的分区大小?两个来源:

  1. 原镜像的大小(raw格式的system.img体积,就是原始分区的近似大小,注意有些厂商的system.img并不是完整分区大小)。
  2. 设备上执行df -h /systemcat /proc/partitions看到的大小。

打包命令示例:

make_ext4fs -s -l 3145728000 system_new.img /mnt/system

-l参数的单位是字节,也可以直接用-L指定大小加单位,比如-l 3G-s参数表示生成sparse格式,如果不需要可以去掉。

新版Android还引入了-T参数,用来指定镜像的时间戳。这个时间戳会影响增量OTA的比对,自己刷机的话影响不大,但如果将来要做OTA包,最好保持和原镜像一致。

5.2 AVB校验与dm-verity:改完系统无法开机的元凶

现代Android设备基本都启用了AVB(Android Verified Boot)和dm-verity。简单说,bootloader在启动时会校验system分区的哈希树,如果镜像被改动而校验没同步更新,设备会判定系统被篡改,直接拒绝启动,表现就是开机卡在logo、无限重启、或者直接进bootloader/Recovery并要求恢复出厂。

这个问题有几种解法:

  • 刷入禁用了AVB的boot/recovery。很多第三方Recovery(如TWRP)自带禁用dm-verity的选项,刷完再刷修改过的system.img就行。
  • 用工具重签镜像。需要用到AVB工具链(avbtool),手动计算并写入新的哈希。这个操作复杂度较高,适合对AVB机制有一定理解的玩家。
  • 刷入前先确认设备的bootloader是否解锁。未解锁的bootloader基本不允许刷任何非官方签名的镜像。

我的建议是:如果是刚接触system.img修改,优先考虑关闭AVB或使用已禁用的第三方Recovery,等技术熟练了再研究重签这条硬核路线。另外,每次刷写前记得完整备份原镜像和分区数据,这个习惯能救你很多次。

5.3 修改后无法开机?按这个顺序排查

如果刷完新镜像,手机卡在开机画面,别慌。多数情况下不是设备坏了,而是下面这几个原因之一:

  1. 文件系统大小不对:打包时-l参数设的分区大小和实际分区不匹配。重新确认分区大小再打包。
  2. 删除系统关键文件:精简应用时手一抖,把framework相关的东西删了。检查你删了什么,必要的话把/system/framework目录下的核心jar包恢复回去。
  3. 权限或属主错误:新加进镜像的文件,如果owner不是root或者权限不对(比如可执行文件没加x权限),开机时会因为权限问题崩溃。在Linux下用sudo chown root:rootsudo chmod修正。
  4. 没关AVB/dm-verity:改完镜像没处理签名校验,被安全机制拦截了。
  5. selinux上下文不一致:Android启用SELinux后,系统文件都有特定的安全上下文标签(security context)。新加的文件如果没有正确的上下文,会被SELinux拒绝访问。打包时用make_ext4fs -S file_contexts指定上下文文件,这个文件可以从原镜像里提取,路径一般是/system/etc/selinux/plat_file_contexts或设备上的/file_contexts

第5条是很多人忽略的坑。自行修改系统后开不了机,十有七八和SELinux标签有关。打包命令里加上-S参数指到对应的file_contexts文件,能解决一大批"莫名其妙"的开机问题。

6. 实测高频报错与应对思路

最后这部分,汇总几个实操中反复出现的报错和我的排查思路。这些报错信息看起来各不相同,但多数根源其实落在同一个地方——格式没分清或打包参数不对。

报错一:mount: wrong fs type, bad option, bad superblock看到这个,第一反应是去看这个镜像到底是不是ext4。用file看一眼,如果之前忘了转sparse,这里就会报这个错。解决办法:先simg2img转格式再挂载。还有一种情况是镜像本身损坏了,先用simg2img转raw后用e2fsck -f修复。

报错二:e2fsck: Attempt to read block from filesystem resulted in short read这个多半是文件系统大小和镜像文件实际大小不一致。检查一下你是不是直接拿一个sparse镜像强行跑了e2fsck,或者打包时-l参数写错了。解决办法:确认镜像已经是raw格式,并且文件大小和文件系统声明的大小一致。

报错三:make_ext4fs: No such file or directory这个很乌龙,通常是工作目录或路径引号的问题。你有可能是从Windows共享目录直接操作的,路径里有空格或中文。统一把镜像和文件树考到Linux本地目录下再执行,路径里不要有中文和空格。

报错四:selinux: avc: denied ...这是SELinux拒绝访问的日志。修改过的文件缺少正确的上下文标签。在打包时补上-S file_contexts参数。如果不知道file_contexts文件在哪,从原system.img挂载后的/system/etc/selinux/目录下找,或者从设备上提取。

报错五:erofs挂载报错或mkfs.erofs版本过旧新设备用的erofs版本可能比发行版仓库里的新,报错通常是superblock信息无法识别。解决办法是从erofs官方仓库编一份最新版的erofs-utils,老版本不认新格式是常见问题。

这些报错在搞过几次镜像修改后,基本都能一眼定位。关键还是回到第2节说的那句话——先判断格式,再选工具链。格式判断不出错,后面九成的问题都不会发生。


最后分享一个我自己的习惯:无论改什么镜像,动手之前先把原始文件做一份备份,放在另一个目录、另一块硬盘、或者直接压缩存档。改坏了随时能回到起点重新来过,这比任何技巧都重要。

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

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

立即咨询