fuqiuluo’s blog

记录美好生活

日志记录

一个藏在 app_zygote 里的 SELinux Policy Oracle

#KSU#安全#安卓
type
Post
status
Published
date
May 10, 2026
slug
summary
一个利用 Android 原生 app_zygote 机制的KernelSU检测。
tags
KSU
安全
安卓
category
日志记录
icon
password
page icon
最近验证了一个比较有意思的 Android root 检测点:
它不查 su,不查 /proc/maps,不查 mount,也不直接检测 Zygisk。
它利用 Android 原生的 Application Zygote 机制,让检测代码运行在 app_zygote SELinux 域里,然后借助 AOSP policy 里赋予 app_zygote 的权限,查询当前内核正在生效的 live sepolicy。
如果设备上的 root 方案修改过 sepolicy,并留下了类似 magisk_file、ksu_file 这样的 type,就可能被直接问出来。
参考原文:private/app_zygote.te - platform/system/sepolicy - Git at Google
思路:@aviraxp

背景

AOSP 里有这么几条规则:
它们的含义是:允许 app_zygote 检查 SELinux context 是否有效,以及检查某个访问决策是否被允许。
普通 App 一般没有这个能力。
但如果 App 声明了:
系统会启动一个 application-specific zygote,并在 ZygotePreload.doPreload() 中执行 App 提供的 preload 代码。
此时执行上下文是:u:r:app_zygote:s0
这就变成了一个很微妙的入口:普通 App 可以间接让自己的代码在 app_zygote 域执行一小段逻辑。

检测原理

核心不是“检测 Zygisk 文件”,而是把 app_zygote 当成一个 SELinux policy oracle
例如查询:
在 stock 系统上,这些 root 相关 context 通常应当不存在。
但某些 root 方案为了模块系统、systemless mount、权限放行等功能,可能会向 live sepolicy 注入新的 type 或 allow rule。
这时 app_zygote 的 SELinux 查询能力就能把这些痕迹问出来。

实测结果

在一台 SukiSU root 设备上,普通 App 进程中查询失败:
errno=13 表示普通 App 没权限问。
但在 app_zygote preload 中:
并且访问决策也命中:
这说明这台设备的 live sepolicy 中确实存在非 stock 的 root/module 相关 type 和规则。
另一台设备中,同样的查询结果是:
errno=22 在这里表示:app_zygote 有权限问,但该 context 在当前 policy 中不存在。
也就是这组检测未命中。

它能检测什么

这个方法更准确地说,是检测:
触碰过 SELinux policy 的 root 或模块系统痕迹。
可以检测到的可能包括:
  • 新增的 root 相关 SELinux type
  • magisk_file、ksu_file 等模块系统痕迹
  • stock 系统不应存在的 context
  • 异常宽松的 allow rule
  • 模块自定义 sepolicy.rule 留下的痕迹
它不等价于:
  • 检测 Zygisk 是否正在运行
  • 检测设备是否一定 root
  • 检测所有 root 方案

局限性

这个点不是万能的。如果 root 方案 (例如APatch) 没有修改 sepolicy,或者做了更克制的 patch,可能不会命中。如果对方改名、定制 type,固定字典也可能查不到。
另外,OEM ROM 本身可能存在一些特殊 policy,所以实际使用时需要按 ROM、Android 版本、设备型号建立 baseline,避免误报。

附件

Loading...