首页
社区
课程
招聘
[原创] Android Root 环境隐藏:SELinux 查询探测与对抗
发表于: 14小时前 410

[原创] Android Root 环境隐藏:SELinux 查询探测与对抗

14小时前
410

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编辑 ,原因:
收藏
免费 19
支持
分享
最新回复 (6)
雪    币: 1
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
酷酷
14小时前
0
雪    币: 7613
活跃值: (24531)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
3
看看
13小时前
0
雪    币: 173
活跃值: (330)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
学习
4小时前
0
雪    币: 6146
活跃值: (10972)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
3小时前
0
雪    币: 76
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
学习
2小时前
0
雪    币: 4140
活跃值: (6777)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
感谢分享
1小时前
0
游客
登录 | 注册 方可回帖
返回