最近收到一些报告,称 Shamiko 无法绕过中国农业银行等应用的检测。调查后发现,这些用户均是使用了 Magisk + ZygiskNext 的组合,且 Shamiko 等隐藏模块运行在黑名单模式。
阅读 ZygiskNext 源码[1][2]后发现,ZygiskNext 虽然支持读取 Magisk 排除列表,但实现方式仍然比较简单(简陋?),具体来说,有以下几个问题:
一是性能损耗。ZygiskNext 在判断进程是否被排除、是否具有 su 权限、是否为 Magisk 管理器等多个场景中,需要多次执行 magisk --sqlite 命令读取数据库。其中某些场景在任意 app 启动时都会触发,从而拖慢应用启动速度(虽然感知不明显)。
二是 API 行为差异。虽然 ZygiskNext 声称与原版 Zygisk API 保持行为一致,但 ZygiskNext 处理模块 flag 的最小单元是 uid,而非进程。将某个进程加入排除列表,等同于将该进程 uid 对应的所有进程都加入排除列表(一键全选)。究其原因,可能是由于 ZygiskNext 起初是为 KernelSU 专门设计的,而 KernelSU 并没有将管理的颗粒度细分到进程。这个行为差异可能会影响到模块挂载,但在实际使用中,产生问题的概率很小。
三是(暂时)无法判断隔离进程。普通应用的 uid 是固定的,而隔离进程(isolated process)的 uid 在每次创建时都是随机的,ZygiskNext 目前还无法判断隔离进程是否处于排除列表中,也无法正确执行相应的 unmount 等操作,从而影响隐藏效果。Magisk 有一系列复杂的函数处理这个问题[3],ZygiskNext 尚未实现它们。这点在 ZygiskNext 的更新日志中也有说明,但被大多数人忽略了。若要在上述环境下使用 Shamiko,请打开白名单模式。
综上,不推荐在 Magisk 上使用 ZygiskNext。目前原版 Magisk 采用的 native bridge 加载方式搭配 Shamiko,仍能对市面上绝大多数(甚至所有) app 实现很好的隐藏。
[1] https://github.com/Dr-TSNG/ZygiskNext/blob/338d306501ce6437807f66d9e4f179dc5b0d1a8f/zygiskd/src/zygiskd.rs#L244
[2] https://github.com/Dr-TSNG/ZygiskNext/blob/338d306501ce6437807f66d9e4f179dc5b0d1a8f/zygiskd/src/root_impl/magisk.rs
[3] https://github.com/topjohnwu/Magisk/blob/b04e1394c0dadbfd1314cc999f367a9a9781cfd8/native/src/core/deny/utils.cpp
阅读 ZygiskNext 源码[1][2]后发现,ZygiskNext 虽然支持读取 Magisk 排除列表,但实现方式仍然比较简单(简陋?),具体来说,有以下几个问题:
一是性能损耗。ZygiskNext 在判断进程是否被排除、是否具有 su 权限、是否为 Magisk 管理器等多个场景中,需要多次执行 magisk --sqlite 命令读取数据库。其中某些场景在任意 app 启动时都会触发,从而拖慢应用启动速度(虽然感知不明显)。
二是 API 行为差异。虽然 ZygiskNext 声称与原版 Zygisk API 保持行为一致,但 ZygiskNext 处理模块 flag 的最小单元是 uid,而非进程。将某个进程加入排除列表,等同于将该进程 uid 对应的所有进程都加入排除列表(一键全选)。究其原因,可能是由于 ZygiskNext 起初是为 KernelSU 专门设计的,而 KernelSU 并没有将管理的颗粒度细分到进程。这个行为差异可能会影响到模块挂载,但在实际使用中,产生问题的概率很小。
三是(暂时)无法判断隔离进程。普通应用的 uid 是固定的,而隔离进程(isolated process)的 uid 在每次创建时都是随机的,ZygiskNext 目前还无法判断隔离进程是否处于排除列表中,也无法正确执行相应的 unmount 等操作,从而影响隐藏效果。Magisk 有一系列复杂的函数处理这个问题[3],ZygiskNext 尚未实现它们。这点在 ZygiskNext 的更新日志中也有说明,但被大多数人忽略了。若要在上述环境下使用 Shamiko,请打开白名单模式。
综上,不推荐在 Magisk 上使用 ZygiskNext。目前原版 Magisk 采用的 native bridge 加载方式搭配 Shamiko,仍能对市面上绝大多数(甚至所有) app 实现很好的隐藏。
[1] https://github.com/Dr-TSNG/ZygiskNext/blob/338d306501ce6437807f66d9e4f179dc5b0d1a8f/zygiskd/src/zygiskd.rs#L244
[2] https://github.com/Dr-TSNG/ZygiskNext/blob/338d306501ce6437807f66d9e4f179dc5b0d1a8f/zygiskd/src/root_impl/magisk.rs
[3] https://github.com/topjohnwu/Magisk/blob/b04e1394c0dadbfd1314cc999f367a9a9781cfd8/native/src/core/deny/utils.cpp
GitHub
ZygiskNext/zygiskd/src/zygiskd.rs at 338d306501ce6437807f66d9e4f179dc5b0d1a8f · Dr-TSNG/ZygiskNext
Standalone implementation of Zygisk. Contribute to Dr-TSNG/ZygiskNext development by creating an account on GitHub.
Magisk 27.0 正式版发布后,我们收到了一些报告,称 WiFi 无法打开(如[1])。调查后发现,这与 Magisk 近期修复的一个安全问题有关。
众所周知,Magisk 有一个基础功能,就是自定义 sepolicy 规则。为了实现这个功能,Magisk 需要劫持 sepolicy 加载过程,读取设备上原本的 sepolicy,修补后将其手动加载进内核。这个步骤很复杂,需要调用 SELinux Project 提供的 libsepol 库。由于 Android 自带的 libsepol 缺少某些导出函数,且对规则的检查过于严格,Magisk 一直以来使用的都是自行编译的 libsepol。
问题就出在这里。直到去年年底,Magisk 使用的 libsepol 都是从上游 SELinux Project fork 的。AOSP 使用的 libsepol 也同样是从上游 fork 的,在 Android 11 前变动不大;但从 Android 11 开始,为了能够限制应用读取 MAC 地址[2],谷歌对内核、libsepol、内置 selinux 规则做了一些小小的修改,使系统能够识别 RTM_GETLINK 消息,并针对性加以限制[3]。这些修改并未进入上游。
篇幅原因,具体技术细节不再详述,只需要知道大致流程:libsepol 在向内核写入规则时,传递一个标记,告知内核需要对 RTM_GETLINK 消息进行特殊的权限控制。由于 Magisk 直接使用从上游 fork 的 libsepol,因此在安装了 Magisk 的设备上,内核压根不知道要对 RTM_GETLINK 消息进行拦截。后果就是,所有应用都可以读取设备 MAC 地址。这个漏洞从 Android 11 发布的那天起就一直存在,直到近期才被发现。
Magisk 27.0 通过从 AOSP fork libsepol 修复了这个问题。但另一个问题随之而来:为了支持 Project Treble,谷歌将相应的内核提交同步到了 common kernel 的 Android 9 分支,导致部分 Android 9 设备的内核也有限制读取 MAC 地址的能力。在正常情况下,这毫无问题:用户空间的 libsepol 并不会传递相应标记,因此该功能不会启用。但是,如果用户安装了修复安全问题后的 Magisk,内核中的功能会被启用,但 Android 9 系统并没有相应的 selinux 规则来告知内核,不需要限制系统应用读取 MAC 地址。从而,在这部分设备上,WiFi 根本无法打开。
我目前想到的修复方法有两种,一是根据设备原有 libsepol 实现,判断是否应该向内核传递 flag,或者为不同 Android 版本编译不同的 libsepol;二是干脆直接向内核写入相匹配的 sepolicy 规则,允许系统应用获取 MAC 地址。具体怎么修,还要看项目维护者的选择。
[1] https://github.com/topjohnwu/Magisk/issues/7764
[2] https://developer.android.com/training/articles/user-data-ids#mac-11-plus
[3] https://android-review.googlesource.com/c/platform/external/selinux/+/1229615; https://android-review.googlesource.com/c/kernel/common/+/1214053; https://android-review.googlesource.com/c/platform/system/sepolicy/+/1214045
众所周知,Magisk 有一个基础功能,就是自定义 sepolicy 规则。为了实现这个功能,Magisk 需要劫持 sepolicy 加载过程,读取设备上原本的 sepolicy,修补后将其手动加载进内核。这个步骤很复杂,需要调用 SELinux Project 提供的 libsepol 库。由于 Android 自带的 libsepol 缺少某些导出函数,且对规则的检查过于严格,Magisk 一直以来使用的都是自行编译的 libsepol。
问题就出在这里。直到去年年底,Magisk 使用的 libsepol 都是从上游 SELinux Project fork 的。AOSP 使用的 libsepol 也同样是从上游 fork 的,在 Android 11 前变动不大;但从 Android 11 开始,为了能够限制应用读取 MAC 地址[2],谷歌对内核、libsepol、内置 selinux 规则做了一些小小的修改,使系统能够识别 RTM_GETLINK 消息,并针对性加以限制[3]。这些修改并未进入上游。
篇幅原因,具体技术细节不再详述,只需要知道大致流程:libsepol 在向内核写入规则时,传递一个标记,告知内核需要对 RTM_GETLINK 消息进行特殊的权限控制。由于 Magisk 直接使用从上游 fork 的 libsepol,因此在安装了 Magisk 的设备上,内核压根不知道要对 RTM_GETLINK 消息进行拦截。后果就是,所有应用都可以读取设备 MAC 地址。这个漏洞从 Android 11 发布的那天起就一直存在,直到近期才被发现。
Magisk 27.0 通过从 AOSP fork libsepol 修复了这个问题。但另一个问题随之而来:为了支持 Project Treble,谷歌将相应的内核提交同步到了 common kernel 的 Android 9 分支,导致部分 Android 9 设备的内核也有限制读取 MAC 地址的能力。在正常情况下,这毫无问题:用户空间的 libsepol 并不会传递相应标记,因此该功能不会启用。但是,如果用户安装了修复安全问题后的 Magisk,内核中的功能会被启用,但 Android 9 系统并没有相应的 selinux 规则来告知内核,不需要限制系统应用读取 MAC 地址。从而,在这部分设备上,WiFi 根本无法打开。
我目前想到的修复方法有两种,一是根据设备原有 libsepol 实现,判断是否应该向内核传递 flag,或者为不同 Android 版本编译不同的 libsepol;二是干脆直接向内核写入相匹配的 sepolicy 规则,允许系统应用获取 MAC 地址。具体怎么修,还要看项目维护者的选择。
[1] https://github.com/topjohnwu/Magisk/issues/7764
[2] https://developer.android.com/training/articles/user-data-ids#mac-11-plus
[3] https://android-review.googlesource.com/c/platform/external/selinux/+/1229615; https://android-review.googlesource.com/c/kernel/common/+/1214053; https://android-review.googlesource.com/c/platform/system/sepolicy/+/1214045
GitHub
WiFi not working due to new sepolicy flag · Issue #7764 · topjohnwu/Magisk
After trying to update to Magisk 27.0 (27001) on Android 10, WiFi still says "IP configuration failed" and WiFi doesn't work. However, with Magisk 26.4 (26400), the WiFi works fine. D...
Android 版本升级带来的某些行为改变不会体现在更新日志中,但会大幅度影响使用体验。例如 Android 14 在强行停止应用前冻结其 cgroup,有效解决了应用通过不断 fork 进程互相保活的问题[1]。
在权限控制方面也有类似的变化。从 Android 14 开始,普通应用将无法读取 ro.debuggable 和 ro.secure 两个系统属性[2][3]。这对使用第三方 ROM 的隐藏魔人来说,无疑是个好消息:许多应用通过这两个属性来判断系统是否为 userdebug 或 eng 构建。
看起来很美好,对吧?我第一时间在手上的一加 Ace 2 Pro(运行 ColorOS 14)进行了实验。却发现仍可以通过在终端运行 getprop 获得这两个属性的值。使用 magiskpolicy dump 出系统 sepolicy 后,借高人慧眼,发现这样一条:
表示所有 selinux domain 都可以读取这两个属性的值。这在 AOSP 中是一个 neverallow 条目。这说明,ColorOS 在构建时修改了 neverallow 规则或者直接允许了 neverallow,并且没有运行 CTS 测试。
由于时间原因,我没有继续研究,但恐怕类似的情况不只这一例,也不知是否会导致更严重的隐私泄露与安全问题。只能对 ColorOS 质量一声叹息。
[1] https://www.tgoop.com/vvb2060Channel/810
[2] https://android.googlesource.com/platform/system/sepolicy/+/d0e108fbbef339063893f3eca0aaabdd3dbe00a6
[3] https://android.googlesource.com/platform/system/sepolicy/+/8a7dcb5e1e2bd172de4191286f130823de02958c
在权限控制方面也有类似的变化。从 Android 14 开始,普通应用将无法读取 ro.debuggable 和 ro.secure 两个系统属性[2][3]。这对使用第三方 ROM 的隐藏魔人来说,无疑是个好消息:许多应用通过这两个属性来判断系统是否为 userdebug 或 eng 构建。
看起来很美好,对吧?我第一时间在手上的一加 Ace 2 Pro(运行 ColorOS 14)进行了实验。却发现仍可以通过在终端运行 getprop 获得这两个属性的值。使用 magiskpolicy dump 出系统 sepolicy 后,借高人慧眼,发现这样一条:
allow domain userdebug_or_eng_prop file { read getattr map open }
表示所有 selinux domain 都可以读取这两个属性的值。这在 AOSP 中是一个 neverallow 条目。这说明,ColorOS 在构建时修改了 neverallow 规则或者直接允许了 neverallow,并且没有运行 CTS 测试。
由于时间原因,我没有继续研究,但恐怕类似的情况不只这一例,也不知是否会导致更严重的隐私泄露与安全问题。只能对 ColorOS 质量一声叹息。
[1] https://www.tgoop.com/vvb2060Channel/810
[2] https://android.googlesource.com/platform/system/sepolicy/+/d0e108fbbef339063893f3eca0aaabdd3dbe00a6
[3] https://android.googlesource.com/platform/system/sepolicy/+/8a7dcb5e1e2bd172de4191286f130823de02958c
Telegram
南宫雪珊
Freeze package cgroup before killing
Apps are able to prevent their death by forking multiple processes under different services and monitoring for the death of any of these. When a child death is detected, the remaining process restarts the terminating/terminated…
Apps are able to prevent their death by forking multiple processes under different services and monitoring for the death of any of these. When a child death is detected, the remaining process restarts the terminating/terminated…
https://github.com/canyie/SettingsFirewall
市面上有一些用于阻止应用获取开发者选项、USB 调试、无障碍服务等状态的模块,但大多需要 hook 相应 app,带来新的检测点。
canyie 开发的这款应用 hook SettingsProvider,替换相应设置字段的返回值,从而实现阻止效果。图上有一些常见字段的替换结果,供参考。
注意:应用不止有一种方法判断设备是否处于异常环境。例如,还可以调用这个 api 判断无障碍服务状态:android.view.accessibility.AccessibilityManager.isEnabled()
市面上有一些用于阻止应用获取开发者选项、USB 调试、无障碍服务等状态的模块,但大多需要 hook 相应 app,带来新的检测点。
canyie 开发的这款应用 hook SettingsProvider,替换相应设置字段的返回值,从而实现阻止效果。图上有一些常见字段的替换结果,供参考。
注意:应用不止有一种方法判断设备是否处于异常环境。例如,还可以调用这个 api 判断无障碍服务状态:android.view.accessibility.AccessibilityManager.isEnabled()
Forwarded from 小页页的胡言乱语 (canyie | 愿你开开心心)
Android 11 中引入的软件包可见性(package visibility, https://developer.android.com/training/package-visibility )可以过滤应用能够访问的应用列表,但实际上是鸡肋功能
一方面,该功能虽然对 PM API 及其他一些 API (如 getDefaultSmsPackage)返回的结果进行了过滤,但系统中仍然存在大量 API 允许应用违反可见性获得未知包,如 AccessibilityManager.getEnabledAccessibilityServiceList() 允许应用获得正在运行的无障碍服务列表,还有 Settings API 允许应用通过读取系统设置的方式获得无障碍服务列表及通知监听器列表等
另一方面,系统中存在大量漏洞允许应用绕过软件包可见性查询指定软件包是否存在,以 CVE-2021-0975 为例,该漏洞允许攻击者通过系统抛出的异常信息中的微小差异判断软件是否已被安装。对应补丁在 https://cs.android.com/android/_/android/platform/frameworks/base/+/bf0d59726a0d9973f6867faedac0fe476c81fe8b
类似的漏洞 Google 给予的评级一直都是 Moderate severity 因此只在 Android 大版本迭代时对其进行修复。这种漏洞还有多少,我简单检索了一下,仅仅只是 Android 14 中修复的有 CVE 编号的漏洞就至少有图上这些。同时,2023 年 5 月起大部分 moderate 漏洞不会再被授予 CVE 编号,被默默修复而不为人所知的漏洞又会有多少呢?
注:即使使用 HideMyApplist 这样的 Xposed 模块,也无法阻止软件通过上述方式违规获得信息。不排除未来会有软件利用这种方式绕过用户安装的 HideMyApplist 等模块获取敏感应用(如 Magisk/KernelSU manager)信息。如果想治住这些软件,稍微靠谱一点的方法是利用多用户,把它们扔一个单独的用户里。一般情况下,能够跨越用户边界访问其他用户数据的漏洞 Google 至少都会评级为 High severity 因此能够在每月安全补丁中修复。注意必须是完全用户,使用 work profile 是不行的。
一方面,该功能虽然对 PM API 及其他一些 API (如 getDefaultSmsPackage)返回的结果进行了过滤,但系统中仍然存在大量 API 允许应用违反可见性获得未知包,如 AccessibilityManager.getEnabledAccessibilityServiceList() 允许应用获得正在运行的无障碍服务列表,还有 Settings API 允许应用通过读取系统设置的方式获得无障碍服务列表及通知监听器列表等
另一方面,系统中存在大量漏洞允许应用绕过软件包可见性查询指定软件包是否存在,以 CVE-2021-0975 为例,该漏洞允许攻击者通过系统抛出的异常信息中的微小差异判断软件是否已被安装。对应补丁在 https://cs.android.com/android/_/android/platform/frameworks/base/+/bf0d59726a0d9973f6867faedac0fe476c81fe8b
类似的漏洞 Google 给予的评级一直都是 Moderate severity 因此只在 Android 大版本迭代时对其进行修复。这种漏洞还有多少,我简单检索了一下,仅仅只是 Android 14 中修复的有 CVE 编号的漏洞就至少有图上这些。同时,2023 年 5 月起大部分 moderate 漏洞不会再被授予 CVE 编号,被默默修复而不为人所知的漏洞又会有多少呢?
注:即使使用 HideMyApplist 这样的 Xposed 模块,也无法阻止软件通过上述方式违规获得信息。不排除未来会有软件利用这种方式绕过用户安装的 HideMyApplist 等模块获取敏感应用(如 Magisk/KernelSU manager)信息。如果想治住这些软件,稍微靠谱一点的方法是利用多用户,把它们扔一个单独的用户里。一般情况下,能够跨越用户边界访问其他用户数据的漏洞 Google 至少都会评级为 High severity 因此能够在每月安全补丁中修复。注意必须是完全用户,使用 work profile 是不行的。
Forwarded from 5ec1cff
Zygisk-Next-v4-0.9.2.1-209-ca224a3-release.zip
1.7 MB
- 不同 abi 使用同一个 daemon
- 简单的 webui
- 简单的 webui
Forwarded from 5ec1cff (5ec1cff)
钱庄
Zygisk-Next-v4-0.9.2.1-209-ca224a3-release.zip
- 缩减了模块信息
- 可能产生行为变化
测试版,请 zygisk-clipboard-whitelist 用户测试能否正常使用
另:招 WebUI 设计一人
- 可能产生行为变化
测试版,请 zygisk-clipboard-whitelist 用户测试能否正常使用
公开一个针对 KernelSU 的侧信道攻击方案,可用于检测(已于 0.8.0+ 中修复,建议尽快更新内核;侧信道攻击的定义请自行阅读维基百科)。
先来梳理 KernelSU 的核心工作流程。KernelSU 通过
需要注意的是,
早在去年 3 月,就有人发现可以通过分别多次调用
查看代码发现,
答案是肯定的。上个月,有人报告 Payback、Vietbank 等应用可检测到搭载了 KernelSU 的内核[4]。使用
修复也很简单:当操作失败一次之后,直接拉黑对应的
[1] https://github.com/tiann/KernelSU/blob/dbe43b15407950f268a29b094525bb0cca734d31/kernel/core_hook.c#L202
[2] https://github.com/tiann/KernelSU/issues/300
[3] https://github.com/tiann/KernelSU/commit/814d65cc28331da6e3518b3df65952eff5ed4be7
[4] https://github.com/tiann/KernelSU/issues/1328
[5] https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/arch_timer.txt
[6] https://github.com/tiann/KernelSU/commit/07e475c5dc80b888c059a28fae1c852830bf6bbd
[7] https://github.com/tiann/KernelSU/issues/836
先来梳理 KernelSU 的核心工作流程。KernelSU 通过
kprobe
(或在编译时安插 hook)劫持 prctl
系统调用,用户侧主动调用 option
为 0xdeadbeef
的 prctl
与内核交互,内核根据用户侧的指令控制进程行为。KernelSU 最主要的功能(如管理器鉴权、提权 root
、unmount
等)都是这样实现的,具体的逻辑参见 ksu_handle_prctl
函数。[1]需要注意的是,
prctl
是一个很常见的系统调用,所有应用都可以主动调用它,而正常的内核是不会有 0xdeadbeef
这个 option
的。这并不会导致函数返回值差异,但相比正常设备,在处理这个的 prctl
时,内核搭载 KernelSU 的设备要多执行一段代码,换句话说,会更慢。这给时间侧信道攻击带来了可乘之机。早在去年 3 月,就有人发现可以通过分别多次调用
option
为 0xdeadbeef
和 0xdead0000
(这个 option
显然不存在,因此内核会直接返回错误,时间很快)的不同 prctl
,比较指令执行时间来判断 KernelSU
是否存在[2] 。拜某检测器所赐,这个问题很快得到了修复[3],调查结果是一行日志拖慢了执行速度(见 147 行),注释掉即可。此外,这个修复对管理器或 root
进程才有权执行的请求,还进行了提前鉴权,以便进一步降低执行时间。查看代码发现,
ksu_handle_prctl
中要处理的大多数请求比较简单,很难导致有统计意义的时间差异。但不知为何,上面的修复并没有处理 CMD_BECOME_MANAGER
这个最复杂的请求路径。这个参数用于确定并鉴权 KernelSU 管理器,包括路径检查、权限检查、签名检查等多个步骤,会不会隐藏着攻击点呢?答案是肯定的。上个月,有人报告 Payback、Vietbank 等应用可检测到搭载了 KernelSU 的内核[4]。使用
stackplz
截获系统调用后,发现 CMD_GET_VERSION
和 CMD_BECOME_MANAGER
分别被调用了两千次:[1619|1619|.client.android] prctl(option=-559038737, arg2=2, arg3=549737147384, arg4=4095, arg5=0, ret=-22)
[1619|1619|.client.android] prctl(option=-559038737, arg2=1, arg3=8, arg4=531642947800, arg5=0, ret=-22)
CMD_GET_VERSION
分支在一开始就会做权限检查,执行很快。CMD_BECOME_MANAGER
首先要从用户空间复制内存,还要做路径检查、签名验证,肯定会慢一些,但会慢得这么明显吗?继续研究,我们发现,相比使用 gettimeofday
等微秒级精度的 syscall
获取时间,这两款应用调用了 armv8
处理器搭载的 arch_timer
硬件,通过读取 CNTVCT_EL0
和 CNTFRQ_EL0
两个寄存器达到精确计时。目前主流骁龙处理器的计时器频率是 19.2 MHz,精度可以达到 5 纳秒左右。[5]修复也很简单:当操作失败一次之后,直接拉黑对应的
uid
,不允许下次调用[6]。这样即使慢,也只有第一次会慢,在统计上没有任何意义,不能用于生产环境检测。其实 weishu 自己也提出了更好的修复方式:要么开机时主动扫描应用,由内核确定管理器;要么抛弃管理器,使用 webui。至于还有没有其他的攻击方式,各位可以自行探索。例如去年 Mufanc 提出的方案[7],使用 mincore
检查缺页异常是否触发,从而判断内存是否有异常访问(这个检测方式也常用于游戏外挂检测)。[1] https://github.com/tiann/KernelSU/blob/dbe43b15407950f268a29b094525bb0cca734d31/kernel/core_hook.c#L202
[2] https://github.com/tiann/KernelSU/issues/300
[3] https://github.com/tiann/KernelSU/commit/814d65cc28331da6e3518b3df65952eff5ed4be7
[4] https://github.com/tiann/KernelSU/issues/1328
[5] https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/arch_timer.txt
[6] https://github.com/tiann/KernelSU/commit/07e475c5dc80b888c059a28fae1c852830bf6bbd
[7] https://github.com/tiann/KernelSU/issues/836
之前提到的 ZygiskNext 三个问题均已在该版本中解决。唯一的缺憾是实现方式依赖(可能不稳定的)Magisk 内部细节,请自行测试与不同 Magisk 发行版的兼容性。
考虑到 topjohnwu 沉迷 rust,对维护 Zygisk 兴趣不大(之前的 Zygisk 更新基本都是外部贡献者在维护),且 native bridge 注入方式在兼容性上相对较差,我个人建议 Magisk 用户也切换至 ZygiskNext。
考虑到 topjohnwu 沉迷 rust,对维护 Zygisk 兴趣不大(之前的 Zygisk 更新基本都是外部贡献者在维护),且 native bridge 注入方式在兼容性上相对较差,我个人建议 Magisk 用户也切换至 ZygiskNext。
Forwarded from 5ec1cff (5ec1cff)
Zygisk-Next-1.0-RC4-254-66a86a1-release.zip
1.6 MB
ZygiskNext 1.0-RC4
- 支持在 Magisk 模式下正确处理隔离进程的 flags ,这意味着 Magisk 中使用 ZygiskNext 时,Shamiko 的黑名单模式可以正常工作。
- 同时解决了 Magisk 模式下的性能问题。
- 由于实现依赖内部细节,不保证修改后的 Magisk 能正常工作。
- Added support for correctly handling isolation process flags in Magisk mode, which means that Shamiko's blacklist mode can function properly when using ZygiskNext in Magisk.
- Resolved performance issues in Magisk mode.
- Due to implementation relying on internal details, there is no guarantee that the modified Magisk will function properly.
- 支持在 Magisk 模式下正确处理隔离进程的 flags ,这意味着 Magisk 中使用 ZygiskNext 时,Shamiko 的黑名单模式可以正常工作。
- 同时解决了 Magisk 模式下的性能问题。
- 由于实现依赖内部细节,不保证修改后的 Magisk 能正常工作。
- Added support for correctly handling isolation process flags in Magisk mode, which means that Shamiko's blacklist mode can function properly when using ZygiskNext in Magisk.
- Resolved performance issues in Magisk mode.
- Due to implementation relying on internal details, there is no guarantee that the modified Magisk will function properly.
今天为了抓包,下载了 zygisk-cacerts 模块 [1]。该模块在 /system/etc/security/cacerts 路径挂载证书,同时通过 zygisk 注入相应应用,设定 system.certs.enabled prop 为 true,从在 Android 14 上允许应用使用来自 system 而非 apex 路径的证书 [2]。但在启用模块后,发现 HttpCanary 还是无法识别系统证书。经过调查,发现这是 Magisk + Zygisk Next 环境特有的问题。
Magisk 在收集模块时,若自带 Zygisk 处于未启用状态,则会忽略所有 Zygisk 模块(注意是全部忽略,包括文件挂载和脚本)[3]。在只存在 Magisk 一种 root 实现的时代,这种做法当然没有问题。但 KernelSU 登场之后,由于并没有自带 Zygisk,因此会忠实地加载全部模块。换句话说,对于同一个 Zygisk 模块,在 KernelSU 上,即使没有安装 Zygisk Next,无法实现注入,文件系统挂载和脚本也会被执行;而在 Magisk 上,若没有开启自带的 Zygisk,这个模块将会被直接忽略。
之前的 Zygisk Next 对 Magisk 这种未公开的行为专门做了兼容,会手动执行模块的所有脚本,但没有处理文件挂载(因为几乎所有常见 Zygisk 模块都不需要挂载文件)。直到今天发布的 1.0 RC5 版本,才通过硬链接模块文件到 Zygisk Next 目录的方式,变相实现了文件挂载。不过说到底,这还是用 hack 代替 hack,我认为最好的处理方式,是暴露一个 Zygisk 是否开启的 API,然后让模块自行处理 Zygisk 兼容性问题。
[1] https://github.com/vvb2060/zygisk_cacerts
[2] https://cs.android.com/android/_/android/platform/frameworks/base/+/86dc3f7afbc06ec63a41c592403721f9c66f85f4
[3] https://github.com/topjohnwu/Magisk/pull/4862/commits/d074dacff0d005a0e46c0d09106f595958b42a7a
Magisk 在收集模块时,若自带 Zygisk 处于未启用状态,则会忽略所有 Zygisk 模块(注意是全部忽略,包括文件挂载和脚本)[3]。在只存在 Magisk 一种 root 实现的时代,这种做法当然没有问题。但 KernelSU 登场之后,由于并没有自带 Zygisk,因此会忠实地加载全部模块。换句话说,对于同一个 Zygisk 模块,在 KernelSU 上,即使没有安装 Zygisk Next,无法实现注入,文件系统挂载和脚本也会被执行;而在 Magisk 上,若没有开启自带的 Zygisk,这个模块将会被直接忽略。
之前的 Zygisk Next 对 Magisk 这种未公开的行为专门做了兼容,会手动执行模块的所有脚本,但没有处理文件挂载(因为几乎所有常见 Zygisk 模块都不需要挂载文件)。直到今天发布的 1.0 RC5 版本,才通过硬链接模块文件到 Zygisk Next 目录的方式,变相实现了文件挂载。不过说到底,这还是用 hack 代替 hack,我认为最好的处理方式,是暴露一个 Zygisk 是否开启的 API,然后让模块自行处理 Zygisk 兼容性问题。
[1] https://github.com/vvb2060/zygisk_cacerts
[2] https://cs.android.com/android/_/android/platform/frameworks/base/+/86dc3f7afbc06ec63a41c592403721f9c66f85f4
[3] https://github.com/topjohnwu/Magisk/pull/4862/commits/d074dacff0d005a0e46c0d09106f595958b42a7a
GitHub
GitHub - vvb2060/zygisk_cacerts
Contribute to vvb2060/zygisk_cacerts development by creating an account on GitHub.
Forwarded from 5ec1cff (5ec1cff)
Zygisk-Next-1.0-RC5-260-bcf0b43-release.zip
1.6 MB
ZygiskNext 1.0-RC5
- Magisk 模式下会挂载 zygisk 模块文件,有助于解决一些模块的兼容性问题
- Magisk 下如果启用自带 zygisk 则会提示错误
- KernelSU webui 微调,需要 11575+ manager
- The zygisk module file will be mounted in Magisk mode, which helps solve some module compatibility issues
- If you enable the built-in zygisk under Magisk, an error will be prompted.
- KernelSU webui fine-tuning, requires 11575+ manager
real5ec1cff
- Magisk 模式下会挂载 zygisk 模块文件,有助于解决一些模块的兼容性问题
- Magisk 下如果启用自带 zygisk 则会提示错误
- KernelSU webui 微调,需要 11575+ manager
- The zygisk module file will be mounted in Magisk mode, which helps solve some module compatibility issues
- If you enable the built-in zygisk under Magisk, an error will be prompted.
- KernelSU webui fine-tuning, requires 11575+ manager
real5ec1cff
前文再续。三个月之后,Magisk 终于修复了这个问题。方法也很简单直接:Magisk 在开机时修补 sepolicy 有两个阶段,第一阶段拦截 init 写入 /sys/fs/selinux/load 的过程,获取原本要写入的 sepolicy 数据库;第二阶段从数据库中 dump 出 policy,在加入 Magisk 自身与模块所需规则后重新编译数据库,再向内核写入。因此,Magisk 可以在第一阶段时读取 init 编译好的数据库携带的 config bits,在第二阶段时直接原样写入内核。
看起来所有问题都得到了修复。然而,根据用户反馈,部分新设备上又出现了任意应用都可以获取 MAC 地址的问题(Native Test 报 Permission Loophole),且这些设备都使用了 live patch (magiskpolicy —live)功能。live patch 的原理,是从 /sys/fs/selinux/policy 读取内核当前加载的 policy 数据库,加入所需条目后重新写入内核。而前述补丁已经按原样写入了 config bits,难道出问题的是内核?
经过进一步调查,我们确认这是一个 AOSP bug。谷歌撰写的两个加入 Android 专用 class 的提交(第一个和第二个),只处理了 policydb_read() 函数,没有处理 policydb_write() 函数。也就是说,用户态可以向内核传递正确的 config,但却无法从内核导出正确的 config。在 live patch 时,内核输出的数据库并不包括前述两个 config,导致 Magisk 在回写内核时,也无法正确处理这两个 config。昨天向 AOSP 提交了补丁,希望能尽快被合并。
怎么修?我有想过在 Magisk 处理,要么在开机时手动保存从 init 读取到的 config,要么直接根据系统版本判断。但考虑到这其实并不是 Magisk 自身的问题,可能还是由谷歌来修复更为合适。对开发者的建议是,在任何情况下,都要优先使用 sepolicy.rule 来修补 sepolicy。
看起来所有问题都得到了修复。然而,根据用户反馈,部分新设备上又出现了任意应用都可以获取 MAC 地址的问题(Native Test 报 Permission Loophole),且这些设备都使用了 live patch (magiskpolicy —live)功能。live patch 的原理,是从 /sys/fs/selinux/policy 读取内核当前加载的 policy 数据库,加入所需条目后重新写入内核。而前述补丁已经按原样写入了 config bits,难道出问题的是内核?
经过进一步调查,我们确认这是一个 AOSP bug。谷歌撰写的两个加入 Android 专用 class 的提交(第一个和第二个),只处理了 policydb_read() 函数,没有处理 policydb_write() 函数。也就是说,用户态可以向内核传递正确的 config,但却无法从内核导出正确的 config。在 live patch 时,内核输出的数据库并不包括前述两个 config,导致 Magisk 在回写内核时,也无法正确处理这两个 config。昨天向 AOSP 提交了补丁,希望能尽快被合并。
怎么修?我有想过在 Magisk 处理,要么在开机时手动保存从 init 读取到的 config,要么直接根据系统版本判断。但考虑到这其实并不是 Magisk 自身的问题,可能还是由谷歌来修复更为合适。对开发者的建议是,在任何情况下,都要优先使用 sepolicy.rule 来修补 sepolicy。
Telegram
钱庄
Magisk 27.0 正式版发布后,我们收到了一些报告,称 WiFi 无法打开(如[1])。调查后发现,这与 Magisk 近期修复的一个安全问题有关。
众所周知,Magisk 有一个基础功能,就是自定义 sepolicy 规则。为了实现这个功能,Magisk 需要劫持 sepolicy 加载过程,读取设备上原本的 sepolicy,修补后将其手动加载进内核。这个步骤很复杂,需要调用 SELinux Project 提供的 libsepol 库。由于 Android 自带的 libsepol 缺少某…
众所周知,Magisk 有一个基础功能,就是自定义 sepolicy 规则。为了实现这个功能,Magisk 需要劫持 sepolicy 加载过程,读取设备上原本的 sepolicy,修补后将其手动加载进内核。这个步骤很复杂,需要调用 SELinux Project 提供的 libsepol 库。由于 Android 自带的 libsepol 缺少某…
一直以来,使用了修改系统叠加层(overlay)模块的用户经常遇到这样的问题:浏览器等使用系统 WebView 的应用打不开或白屏。经过试验,发现关闭 MagiskHide / Zygisk 排除列表 / KSU 模块卸载,浏览器就可以正常打开。近期,我们在排查 ZygiskNext 相关问题时做了一番研究,终于梳理清楚了问题根源。
先来了解一下 Zygote 预加载机制。在 Android 世界中,Zygote 是最先启动的进程,正常情况下,所有系统服务进程和应用进程都是从 Zygote fork 而来,并通过 COW(写时复制)机制,复用 Zygote 的部分物理内存,从而提升应用启动速度,减少资源占用。
因此,Zygote 在启动时,会预先加载一些应用普遍需要用到的库和资源,以避免应用启动时重复加载。预加载的内容主要包括 Java 和 Android 常用类、OpenGL 图形驱动、系统共享库、常用字体、系统资源等。注意,这里的系统资源,既包括 framework-res.apk,也包括目标应用为 android 的 overlay apk。
自 Android N 开始,系统增加了 fd 白名单机制,包括 overlay apk 在内的预加载资源需要在 Zygote fork 为 app 时先关闭一次,再打开。如果在打开时,fd 对应的文件不存在,应用将会直接崩溃。
无论是 MagiskHide 还是 Zygisk 排除列表,主要工作都是将额外挂载的文件 unmount 掉,还给用户一个干净的环境。因此,模块挂载的 overlay apk 也会被卸载,但这并不会影响普通应用,因为 Zygote 只会经历一次 fork(Zygote -> app),在重新打开这个环节,fork 仍未完成,overlay apk 仍是存在于相应 namespace 的,因此,应用并不会崩溃。
但对 child zygote(包括app_zygote 和 webview_zygote),情况有所不同:它们是从 Zygote 孵化的,但也可以再次孵化成隔离进程(isolated process)。也就是说,从 Zygote 到隔离进程,需要经历两次 fork。第一次 fork 如前所述,一切正常;在第二次 fork 时,overlay apk 已经在第一次 fork 后被卸载,不存在于相应 child zygote 的 namespace,但 child zygote 仍持有这些进程的文件描述符。因此,在重新打开这一环节,由于 overlay apk 并不存在,应用将会直接崩溃。
怎么修?说到底,这是 Zygote 的默认行为,因此算不上一个 bug。开发者的选择有很多,在此不再赘述。对用户而言,在使用替换 target 为 android 的 overlay 或 framework jar 的模块前要特别注意,当然,使用 Shamiko 可以解决此问题。
此外,前几天发现,某些 KSU 用户在使用了更改 /vendor 的模块后,如果再进行模块卸载,浏览器也出现了打不开的情况。分析 stacktrace 后发现,似乎是预加载的 OpenGL 驱动出现了某些问题,具体原因还在调查。对于这些用户,可以尝试设置 ro.zygote.disable_gl_preload=1 来关闭 OpenGL 预加载,临时规避这个问题。
先来了解一下 Zygote 预加载机制。在 Android 世界中,Zygote 是最先启动的进程,正常情况下,所有系统服务进程和应用进程都是从 Zygote fork 而来,并通过 COW(写时复制)机制,复用 Zygote 的部分物理内存,从而提升应用启动速度,减少资源占用。
因此,Zygote 在启动时,会预先加载一些应用普遍需要用到的库和资源,以避免应用启动时重复加载。预加载的内容主要包括 Java 和 Android 常用类、OpenGL 图形驱动、系统共享库、常用字体、系统资源等。注意,这里的系统资源,既包括 framework-res.apk,也包括目标应用为 android 的 overlay apk。
自 Android N 开始,系统增加了 fd 白名单机制,包括 overlay apk 在内的预加载资源需要在 Zygote fork 为 app 时先关闭一次,再打开。如果在打开时,fd 对应的文件不存在,应用将会直接崩溃。
无论是 MagiskHide 还是 Zygisk 排除列表,主要工作都是将额外挂载的文件 unmount 掉,还给用户一个干净的环境。因此,模块挂载的 overlay apk 也会被卸载,但这并不会影响普通应用,因为 Zygote 只会经历一次 fork(Zygote -> app),在重新打开这个环节,fork 仍未完成,overlay apk 仍是存在于相应 namespace 的,因此,应用并不会崩溃。
但对 child zygote(包括app_zygote 和 webview_zygote),情况有所不同:它们是从 Zygote 孵化的,但也可以再次孵化成隔离进程(isolated process)。也就是说,从 Zygote 到隔离进程,需要经历两次 fork。第一次 fork 如前所述,一切正常;在第二次 fork 时,overlay apk 已经在第一次 fork 后被卸载,不存在于相应 child zygote 的 namespace,但 child zygote 仍持有这些进程的文件描述符。因此,在重新打开这一环节,由于 overlay apk 并不存在,应用将会直接崩溃。
怎么修?说到底,这是 Zygote 的默认行为,因此算不上一个 bug。开发者的选择有很多,在此不再赘述。对用户而言,在使用替换 target 为 android 的 overlay 或 framework jar 的模块前要特别注意,当然,使用 Shamiko 可以解决此问题。
此外,前几天发现,某些 KSU 用户在使用了更改 /vendor 的模块后,如果再进行模块卸载,浏览器也出现了打不开的情况。分析 stacktrace 后发现,似乎是预加载的 OpenGL 驱动出现了某些问题,具体原因还在调查。对于这些用户,可以尝试设置 ro.zygote.disable_gl_preload=1 来关闭 OpenGL 预加载,临时规避这个问题。
Android 14 QPR2 更新后,部分使用 Hide My Applist 的用户出现了应用打不开或闪退的问题,经调查,我们发现这是 HMA 代码逻辑错误导致的。
HMA 默认打开了「为所有应用启用数据隔离」功能,其具体实现是 hook startViaZygote() 方法,将其中两个参数的值改为 true。在 QPR2 更新后,这个方法的最后增加了一个参数,然而 HMA 寻找参数的方式是从后往前找,因此要 hook 的参数整体向后错位了一个,导致 vold app data 隔离被错误地强制启用,造成应用异常。
已经向 HMA 提交了修复。 在 HMA 还未更新前,用户可以通过关闭「为所有应用启用数据隔离」来规避问题。
更新:已在 CI 版本修复:https://github.com/Dr-TSNG/Hide-My-Applist/actions/runs/8747703933/job/24006580958
HMA 默认打开了「为所有应用启用数据隔离」功能,其具体实现是 hook startViaZygote() 方法,将其中两个参数的值改为 true。在 QPR2 更新后,这个方法的最后增加了一个参数,然而 HMA 寻找参数的方式是从后往前找,因此要 hook 的参数整体向后错位了一个,导致 vold app data 隔离被错误地强制启用,造成应用异常。
已经向 HMA 提交了修复。 在 HMA 还未更新前,用户可以通过关闭「为所有应用启用数据隔离」来规避问题。
更新:已在 CI 版本修复:https://github.com/Dr-TSNG/Hide-My-Applist/actions/runs/8747703933/job/24006580958
Forwarded from 5ec1cff (5ec1cff)
冷知识:Android 中的非 root 用户也可以用 shell 命令,如 am pm 等。
在 termux 等虚拟终端中使用 pm 等命令会提示
因此在没有任何特权的情况下访问 shell command 的正确姿势是提供系统可访问的 fd ,一般来说 app 域的 pipe 都可以被系统访问,因为系统和 app 可能需要通过 pipe 通信。在 shell 中最简单的方法如下(图 2):
思考题(请大家思考,欢迎留言):
0. 这样访问 shell command 是以 shell 的身份还是 app 的身份?是否构成安全威胁?
1. 重定向到文件是否可以正常访问 shell command?App 私有存储(/data)或者扩展存储(/sdcard) 哪一个可用?
2. pm install 命令对传入的 apk 路径同样有权限的要求,请尝试解释原因。
3. 为什么安装了 ksu 或 apatch 后上述限制就消失了?
相关
在 termux 等虚拟终端中使用 pm 等命令会提示
service: Failure calling service xxx
(图1),这并非是说普通 uid 不可使用 shell command ,实际上是因为 shell command 是一个 binder 调用,它会发送调用进程的 stdin, stdout, stderr ,也就是 fd 0, 1, 2 到系统服务,但是如果这三个 fd 有某个是系统服务无法访问的,就会导致 binder 调用失败。一般来说,SELinux 会导致 fd 传递失败。app 域的 devpts 是无法被系统服务访问的,因为没有相关的规则。因此在没有任何特权的情况下访问 shell command 的正确姿势是提供系统可访问的 fd ,一般来说 app 域的 pipe 都可以被系统访问,因为系统和 app 可能需要通过 pipe 通信。在 shell 中最简单的方法如下(图 2):
pm </dev/null 2>&1 | cat
思考题(请大家思考,欢迎留言):
0. 这样访问 shell command 是以 shell 的身份还是 app 的身份?是否构成安全威胁?
1. 重定向到文件是否可以正常访问 shell command?App 私有存储(/data)或者扩展存储(/sdcard) 哪一个可用?
2. pm install 命令对传入的 apk 路径同样有权限的要求,请尝试解释原因。
3. 为什么安装了 ksu 或 apatch 后上述限制就消失了?
相关