尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Magisk 系统定制完全指南:从 boot 镜像修补到 Zygisk 进程注入

Magisk 系统定制完全指南:从 boot 镜像修补到 Zygisk 进程注入 Magisk 系统定制完全指南从 boot 镜像修补到 Zygisk 进程注入【免费下载链接】MagiskThe Magic Mask for Android项目地址: https://gitcode.com/GitHub_Trending/ma/MagiskMagisk 系统定制的核心思路是把 Root 带来的改动从直接刷写/system挪到修补 boot 镜像 运行时动态挂载这条更可控的路径上。它不改只读分区的内容靠 Ramdisk 里的注入二进制接管启动再靠 bind mount 把模块文件叠到系统目录之上。下面按实际会遇到的四类问题展开装不进去、藏不住、改不动、更新会丢。一、先判断设备类型再谈 boot 镜像修补全流程这一节回答为什么同一个 Magisk APK有的设备能正常 Root有的却提示 Ramdisk 不可用。差异不在 Magisk 本身而在这台设备属于哪种启动路径。判断设备属于哪种启动类型Magisk 能装进去的前提是 boot 镜像里有一个它自己能改的 Ramdisk。官方文档 docs/boot.md 把 Android 设备按初始 rootdir / 最终 rootdir分成 A、B、C 三种 boot 方法再叠加 A/B 或 A-only 分区归纳成四种实际形态类型Boot 方法分区2SIboot 里的 Ramdisk对 Root 的意义IA传统 RamdiskA-only否bootramdisk最理想直接修补 bootIIB传统 SARA/B任意recoveryramdisk改的是 recovery 侧IIIBSARA-only任意无只能改 recovery正常启动不带 MagiskIVC2SI任意是Hybrid ramdiskAndroid 10 主流可正常 Root类型 III 是最麻烦的因为 boot 里没有 RamdiskMagisk 只能劫持 recovery 分区于是每次要 Root 都得重启进 recovery。判断依据很简单——打开 Magisk 应用看Ramdisk这一项。图1Home 页的 Ramdisk 一行决定后续走修补 boot还是改 recoveryYes 表示 boot 内含 Ramdisk可走标准修补流程。修补、刷入与 vbmeta 处理确认有 boot Ramdisk 后标准流程是本机取 boot 镜像 → 本机关机修补 → fastboot 刷回。之所以强调必须在目标设备上修补是因为补丁会写入与设备密钥绑定的校验标记跨设备使用会触发验证失败严重时只能清数据恢复。# 在设备端用 Magisk 修补后取回产物并刷回 adb pull /sdcard/Download/magisk_patched_*.img fastboot flash boot magisk_patched_xxxx.img # 若存在独立 vbmeta需禁用 verity/verification可能清数据 fastboot flash vbmeta --disable-verity --disable-verification vbmeta.img刷回后首次启动会提示环境修复按提示重启一次即可。Samsung 设备另有 Knox 锁和必须全量清数据的限制详见 docs/install.md。二、Root 为什么藏得住Magisk 不改只读分区的设计这一节回答既然不碰/system那被替换的文件到底从哪来。答案是挂载时叠加而不是落盘时改写。只读分区是双刃剑现代 Android 对/system、/vendor、/product、/system_ext做 AVB/verity 校验。一旦你直接改写这些分区哪怕是 remount 成 rw块级校验立刻被破坏结果要么启动失败、要么下次 OTA 直接拒装。传统刷入改好系统的 zip做法就卡在这里它把改动写死在只读分区上校验和 OTA 都成了负担。Magisk 的取舍是反过来的——让只读分区保持 100% 原厂所有看起来被改了的文件都是启动后临时叠上去的。代价是每次冷启动都要重新挂载收益是 OTA 几乎不受影响这也是它能长期保留 Root 的根本。用 bind mount 替代改写落盘模块挂载的核心逻辑在 native/src/core/module.rs。它把模块目录的system/递归遍历成一棵FsNode树再按节点类型落地普通文件用bind_mount直接盖到真实路径上遇到 symlink、whiteout删除标记或需要整目录.replace时先在 tmpfs 上搭好结构再整体 bind。关键函数bind_mount末尾还固定做了remount MS_RDONLY把叠上去的内容也锁成只读。// module.rs单个文件节点最终落到真实系统路径并锁成只读 fn bind_mount(reason, src, dest, rec) { src.bind_mount_to(dest, rec).log_ok(); // 盖到 /system/... dest.remount_mount_point_flags(MsFlags::MS_RDONLY).log_ok(); }因为改的是挂载视图而非磁盘内容verity 校验的对象分区字节始终没变这就是无痕的技术来源。删除系统文件则用mknod X c 0 0这种 major/minor 全 0 的哑字符设备当 whiteout挂载时表现为该路径被遮蔽。三、模块与启动脚本改系统不刷机的落地方式这一节回答把一堆文件和一个脚本打包成模块到底由谁、在什么时机执行。答案是一组固定的目录约定加两个启动触发点。模块目录结构与状态标志一个模块就是/data/adb/modules/MODID下的一个文件夹完整约定见 docs/guides.md/data/adb/modules └── $MODID ├── module.prop # 元数据id/name/version/versionCode/... ├── system/ # 会被递归合并进真实 /system含 vendor/product/system_ext │ └── app/... ├── zygisk/ # 各 ABI 的 .so供 Zygisk 注入 ├── skip_mount # 存在则不挂载 system/ ├── disable # 存在则禁用本模块 ├── remove # 存在则下次重启移除 ├── post-fs-data.sh # 早期启动脚本阻塞式 ├── service.sh # 后期启动脚本非阻塞 ├── system.prop # 由 resetprop 加载的属性 └── sepolicy.rule # 额外 SELinux 规则每行一条策略module.prop是严格格式id必须匹配^[a-zA-Z][a-zA-Z0-9._-]$且发布后不可改idmy_module nameMy Module versionv1.0 versionCode1 authordev descriptionreplace and inject some system files updateJsonhttps://example.com/update.jsonpost-fs-data 与 service两个时机怎么选启动触发逻辑在 native/src/core/bootstages.rs。post_fs_data是阻塞式的脚本没跑完或到 40 秒上限前启动会暂停且发生在模块挂载之前适合挂载前动态调整late_start是非阻塞式与启动并行。多数模块只需要service.sh就够了。维度post-fs-datalate_start service是否阻塞启动是最长 40s否并行执行相对模块挂载之前之后是否适合改系统属性危险setprop会死锁须用resetprop -n安全推荐适用场景挂载前微调绝大多数常规脚本需要等待系统完全起来时用resetprop -w sys.boot_completed 0阻塞而不是轮询 sleep。resetprop 与 sepolicy.rule属性与策略的扩展点resetprop是 Magisk 自带的属性工具能读写普通setprop动不了的只读属性sepolicy.rule每行是一条 magiskpolicy 策略语句用于给模块进程补权限等价于调用magiskpolicy --apply加载。两条命令的完整参数见 docs/tools.md。# sepolicy.rule每行一条策略按需给模块进程补权限 allow magiskd system_file:file { read write execute }; allow magiskd system_data_file:dir { search };四、进程级定制Zygisk 的注入时机与边界这一节回答想在自己写的应用进程里、在 framework 完全起来之前跑代码靠什么实现。答案是借ro.dalvik.vm.native.bridge这个属性让每个 app 进程加载一个.so。借 native bridge 完成注入Zygisk 不自己注入而是让 Magisk 在 Zygote 里设置ro.dalvik.vm.native_bridge指向libzygisk.so。这样每一个 app 进程在 specialize 之前都会被 ART 拉去加载它模块的.so就顺势挂在进程里执行。加载逻辑见 native/src/core/zygisk/daemon.rsconst NBPROP: Utf8CStr cstr!(ro.dalvik.vm.native_bridge); const ZYGISKLDR: str libzygisk.so; // 仅当进程未被 denylist 命中、且不是 Magisk 应用时才加载模块 fn zygisk_should_load_module(flags: u32) - bool { flags UNMOUNT_MASK ! UNMOUNT_MASK flags ZygiskStateFlags::ProcessIsMagiskApp.repr 0 }这里有一个容易被忽略的保护Zygote 反复崩溃start_count 3时会自动回滚把注入撤掉避免注入导致 Zygote 反复重启的死循环把设备搞进 bootloop。Zygisk 模块与 denylist 的交互Zygisk 模块放进模块目录的zygisk/下按 ABI 放arm64-v8a.so、x86_64.so等。注意它与隐藏目标是绑定的一旦某进程命中 denylistZygisk 会跳过它UNMOUNT_MASK判断也就是被藏起来的进程同时也不会再被 Zygisk 模块加载。做 Zygisk 模块建议参考官方 zygisk-module-sample 的 API 约定不要自己手写 bridge 加载。五、OTA 与 Root 共存先恢复镜像再走槽位更新这一节回答系统更新时怎么把 Magisk 保住。核心顺序是先恢复原厂镜像过掉 OTA 前置校验更新落到新槽位再往新槽位装 Magisk顺序错了 Root 必丢。先恢复镜像别先重启OTA 前必须先做 Uninstall → Restore Images把被 Magisk 改过的分区从安装时的备份还原成原厂目的是通过 pre-OTA 的块校验。这一步做完不要重启否则等于直接卸载了 Magisk。图2Restore Images 只还原被改过的分区并禁用所有模块用于 OTA 前置校验Complete Uninstall 才是彻底移除。A/B 与 A-only 的两条不同路径A/B 设备可以走更新装进非活动槽位再把 Magisk 装到新槽位全程保留 RootA-only 设备没有这种机制官方给出的也只是最佳实践更新后需要重新 Root且必须保证恢复原厂 recovery。# A/B恢复原厂镜像后正常下 OTA装完两段进度后—— # 1) 不要点“立即重启” # 2) Magisk 应用 → Install → Install to Inactive Slot # 3) 回到系统更新页点“restart now”切到已更新槽位 # 底层由 Magisk 跟踪槽位切换绕过 OTA 后校验设备是否可保 Root关键动作风险点A/B 分区是恢复镜像 → 更新到非活动槽位 → 装到新槽位漏掉不点立即重启会丢A-only 分区否恢复原厂 recovery → 刷原厂 OTA → 重新 Root需电脑自定义 recovery 会干扰前提是全程没自己改过任何只读分区包括没 remount 成 rw否则块校验必破。完整分机型教程见 docs/ota.md。装不进去先看 Home 页 Ramdisk 判断设备类型类型 III 只能走 recovery其余按本机修补 boot fastboot 刷回处理。藏不住根因是只读分区的 AVB/verity 校验Magisk 的对策是保持分区原厂、用 bind mount 在运行时叠加改动。改不动用模块目录 post-fs-data.sh/service.sh两个时机system.prop走 resetprop、sepolicy.rule走 magiskpolicy。更新会丢严格走恢复镜像 → 非活动槽位更新 → 装到新槽位的顺序A-only 设备做好重新 Root 的准备。以上操作均以解锁 Bootloader 为前提会清除设备数据并可能触发厂商保修条款Samsung 会永久触发 Knox请在了解风险且备份数据后操作并仅在自有设备上使用。【免费下载链接】MagiskThe Magic Mask for Android项目地址: https://gitcode.com/GitHub_Trending/ma/Magisk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表