一文读懂 Mountify 核心机制:tmpfs 与 ext4 sparse 双模式完全解析
Mountify 是一款基于 OverlayFS 的全局挂载模块,它能让 KernelSU、APatch 和 Magisk 用户把模块内容以"全局可见"的方式挂载到系统分区之上,而不再依赖传统的 Magic Mount。这篇文章会以新手也能听懂的方式,为你完整拆解 Mountify 的核心机制:tmpfs 模式与 ext4 sparse 模式这两条并行路线,它们各自如何工作、为什么这样设计、以及你该如何选择。
为什么需要 Mountify:传统挂载方式的问题 🤔
在 Mountify 出现之前,主流方案是 Magic Mount 和"ext4 镜像挂载",但两者都有明显缺陷:
- Magic Mount 挂载点爆炸:每挂一个模块就新增多个挂载点,挂载数量暴增后很容易被检测工具(如 zimperium)发现。
- ext4 上挂载点留下痕迹:使用 ext4 镜像作为 OverlayFS 的 upperdir 时,会在
/proc/fs下创建设备节点,同样暴露踪迹。 - F2FS 兼容性问题:F2FS 文件系统配合原生 casefolding 会让 OverlayFS 报错(ovl_dentry_weird),只有 sdcardfs 用户能用
/data作为 overlay 源。
Mountify 的思路完全不同:它把所有模块内容统一复制到一个"假文件夹"(默认名为 mountify),再把这个文件夹通过 OverlayFS 覆盖到各分区。由于模块内容来自同一份上层目录,挂载点数量被大幅压缩,隐蔽性也随之提升。
tmpfs 模式:最推荐的"轻量级"路线 🦾
tmpfs 模式是 Mountify 的默认首选方案,核心依赖是内核开启 CONFIG_TMPFS_XATTR=y。整个流程可以用五步概括:
- 标记跳过:为每个待挂载模块创建
skip_mount标记,让根管理器跳过它们。 - 复制内容:把
/data/adb/modules/模块名的内容复制到/mnt/vendor/mountify(即假文件夹)。 - 镜像 SELinux 上下文:用
chcon --reference逐文件复制原始 SELinux 上下文,避免出现u:object_r:tmpfs:s0这类错误标签。 - 循环处理:对全部模块重复第 2、3 步。
- OverlayFS 挂载:把假文件夹下的
system/bin等目录覆盖挂载到对应的真实分区目录上。
这套逻辑写在 post-fs-data.sh 中,采用两阶段挂载设计:第一阶段把 /mnt 或 /mnt/vendor 挂成 tmpfs,第二阶段再把假文件夹挂成 tmpfs,形成清晰的层级结构。
tmpfs 模式的加分项:诱饵挂载
在 tmpfs 模式下,你还可以开启 test_decoy_mount=1,Mountify 会在一批空白目录(如 /oem、/acct)中寻找"诱饵",把 OverlayFS 的 lowerdir 结构伪装得更像 OEM 出厂挂载(比如 /mnt/vendor/my_bigball 风格)。这是一种反检测的障眼法,让挂载结构看起来更"原生"。
ext4 sparse 模式:为 GPU 驱动等特殊场景而生 🛠️
如果你的内核不支持 tmpfs xattr,或者需要挂载 GPU 驱动这类对文件系统特性敏感的内容,Mountify 会自动切换到 ext4 sparse 模式(sparse 意为"稀疏文件",创建时不实际占用全部磁盘空间)。
它的流程比 tmpfs 多几步:
- 创建
sparse_size(默认 2048MB)大小的稀疏文件mountify-ext4。 - 用
mkfs.ext4格式化成 ext4 文件系统,并去掉 journal 以减小开销。 - 以 loop 方式挂载这个镜像到假文件夹,把模块内容复制进去。
- 复制模块内容并镜像 SELinux 上下文(与 tmpfs 模式相同)。
- 卸载后以只读方式重新挂载,让上层目录变成只读 ext4。
- 最后通过 OverlayFS 覆盖到各分区。
代码层面可以看到,这一步还支持 spoof_sparse=1:Mountify 会模仿 Android 的 APEX 挂载方式,把镜像伪装成 /apex/com.android.mntservice 这样的服务名,让挂载结构看起来像官方行为,相关参数可在 config.sh 中调整。
一个代价:ext4 节点痕迹与"核弹"对策 💣
sparse 模式的代价是:挂载 ext4 镜像会在 /proc/fs 留下 ext4 设备节点,这本身就是一种可被检测的特征。为此 Mountify 提供了两个对策:
- LKM 方案:
enable_lkm_nuke=1可加载一个一次性内核模块 nuke.c,它通过ext4_unregister_sysfs注销掉 ext4 的 sysfs 节点,抹去痕迹。项目预编译了从 Android 4.14 到 6.12 的多个版本,见 module/lkm/,LKM 本身采用 GPLv2 协议。 - ksud 方案:如果你用的是 KernelSU 22105+,内核会自动处理,无需手动加载 LKM。
两种模式怎么选:一张表看懂 👀
| 对比项 | tmpfs 模式 | ext4 sparse 模式 |
|---|---|---|
| 内核要求 | CONFIG_OVERLAY_FS + CONFIG_TMPFS_XATTR | CONFIG_OVERLAY_FS |
| 默认状态 | 首选(xattr 可用时) | 自动回退或 use_ext4_sparse=1 强制 |
| 磁盘占用 | 极小 | 默认预留 2048MB(稀疏文件,实际按需占用) |
| 挂载痕迹 | 少 | 有 ext4 节点,需 LKM 清理 |
| 适用场景 | 常规模块 | GPU 驱动、不支持 tmpfs xattr 的旧内核 |
新手建议:只要能通过安装时的 tmpfs xattr 检测,就保持默认的 tmpfs 模式;只有装 GPU 驱动、或老设备检测失败时,才考虑 sparse 模式。安装时的自动检测逻辑在 customize.sh 中,它会依次测试 overlayfs、tmpfs xattr,最后才尝试 ext4 镜像。
模块管理模式与配置文件速览 📂
Mountify 支持两种挂载范围:
- 自动模式(
mountify_mounts=2):自动挂载所有带 system 文件夹的模块,开箱即用。 - 手动模式(
mountify_mounts=1):只挂载 modules.txt 中列出的模块,适合只想让少数模块"全局化"的场景。
所有持久化配置存放在 /data/adb/mountify/config.sh,你还可以用自带的 WebUI(webui/index.html)进行图形化编辑,对新手非常友好。需要注意几个易踩的坑:
- 卸载模块请配合 NeoZygisk、ReZygisk 等 Zygisk 方案,或在 config.sh 中按你的根管理器设置
MOUNT_DEVICE_NAME。 - 想跳过某个模块的挂载:KernelSU/APatch 上用
skip_mount,Magisk 上用skip_mountify。 - 千万别把
FAKE_MOUNT_NAME改成persist,这会触发脚本的自我保护直接退出。
写在最后:一把锋利的小刀 🔪
Mountify 本质上是在"把模块挂载方式伪装得更接近 OEM 原厂"这条路上做到极致的工具,作者甚至坦言这更像一个"创可贴"方案。它支持 KernelSU metamodule 模式,也兼容 APatch 和 Magisk,安装前请务必确认内核已开启 CONFIG_OVERLAY_FS=y。
搞懂 tmpfs 与 ext4 sparse 双模式的区别,你就掌握了 Mountify 的核心命脉:能用内存就绝不碰磁盘,必须碰磁盘就尽量抹掉痕迹。无论你是刚接触 root 模块的新手,还是追求极致隐蔽的老玩家,希望这篇解析能帮你把这把"小刀"用得又稳又准。😎
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



