LSPosed 团队公布的一个新的 root 检测方案,把查询SELinux policy这种检测方式进行了开源。
如果系统里加载过额外 sepolicy,可能会多出一些 domain、type 或 allow 规则。普通应用虽然不能直接读很多 root 相关文件,但它可以通过系统接口查询某些 SELinux 结果。只要返回值和正常环境不一样,就能变成检测点。
DirtySepolicy 的实现可以简单理解为:用 isolatedProcess 配合 useAppZygote 触发应用私有 Zygote,再通过 zygotePreloadName 把检测代码放到 app_zygote 上下文里执行。只要这个载体能调用 SELinux.checkSELinuxAccess() 向内核查询当前策略,额外 sepolicy 规则就会变成普通应用能读到的信号。
DirtySepolicy 通过 AppZygote 这条链路检测。
配置上大概是这样:
isolatedProcess 配合 useAppZygote 会触发应用私有 Zygote,zygotePreloadName 指向的类会在 preload 阶段执行。DirtySepolicy 在正式查询前还会做一些自检,比如确认 UID 没被换掉、当前 context 是 app_zygote,并比对 getContext()、getPidContext() 和 /proc/self 文件上下文。
自检通过以后,检测点主要落在两个地方。
Java 层可以通过类似下面的接口查询 SELinux 访问结果:
DirtySepolicy 里查询面比较宽,类似这些:
如果这些查询返回 true,应用就能判断 live sepolicy 里可能存在额外规则。
底层会走到 SELinux 的 context 转换和 AV 计算:
对应到内核函数,大概就是:
另一种方式是写:
写入一个目标 context 后,内核会走 SELinux procattr 和 transition 检查。如果返回值不是预期的 EINVAL,也可能被拿来做判断。
对应路径大概是:
检测出来了,那就产生了对抗,最近写了对抗的KPM 模块: selinux-query-guard,用来处理这类 SELinux 查询探测。
做法是在内核 SELinux 相关函数上挂 hook,应用 UID 走到查询入口时,对一些敏感结果做过滤。实现还比较粗,更多是一次针对 DirtySepolicy 思路的 KPM 侧尝试。
selinux-query-guard 加载后会直接安装 hook。
入口:
初始化时调用:
install_hooks() 里通过 kallsyms_lookup_name() 找符号,再用 KernelPatch 的 hook_wrap() 挂回调。
按用途分几类。
这里主要用来观察应用在查什么 context。
如果普通 app 或 isolated app 解析了下面这类 context,就先把这个来源记下来:
SELinux.checkSELinuxAccess() 最后关心的是 av_decision.allowed。
命中敏感来源后,模块会把:
改成:
这样应用看到的就是 deny。
这里没有把所有查询都改掉。代码里保留了一个基础查询能力:
如果把 SELinux 查询能力本身破坏掉,检测样本可能直接报环境异常,所以这块不能粗暴处理。
这里处理 /proc/self/attr/current。
before hook 里记录写入的 name 和 value。
如果是 current,并且 value 是敏感 context,after hook 里再判断是否需要改返回值。
命中后返回:
写 attr current 后,有些内核会继续走 transition 检查。这里也做了返回值过滤,避免从另一条路径露出差异。
模块里放了一个列表:
另外还做了前缀判断:
这块现在写得比较直接。好处是简单,坏处是后续要维护。后面可以考虑把模块加载时机再提前,在 SELinux 初始化完成但脏规则加载之前,先抓一份干净 policy,后续把这份干净策略当白名单来判断查询结果。
不能只看context进行区分。因为系统进程、shell、root 管理器自己也可能查这些东西。直接拦会误伤。
所以模块会记录当前 task 的信息:
分类时先放行 root manager 和 system 这类来源:
然后再判断是否是已经记录过的探测来源:
如果普通 app 或 isolated uid 命中了敏感 context,就记录 UID 和 TGID:
这样做是为了兼容 AppZygote 和 isolatedProcess。检测逻辑可能不在主进程里跑,前一次 context 解析和后一次 AV 查询也不一定完全在同一个进程状态里。
实际修改只有两处。
第一处是返回值:
用于 procattr 和 transition。
第二处是 AV decision:
[培训]《冰与火的战歌:Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于 5小时前
被用户名null编辑
,原因: