type
Post
status
Published
date
Apr 16, 2025
slug
summary
tags
竞赛
Linux
作弊
category
技术分享
icon
password
背景:为什么要做“渲染检测”
在移动端游戏安全对抗里,“外挂在不在渲染”是一个很常见的判据:
- 正常游戏进程会创建图形上下文、提交渲染任务,因此在 GPU/图形驱动相关的内核接口里会留下痕迹。
- 某些作弊/分析进程不会注入目标进程,以降低被发现的概率,但是他们仍旧会调用GPU进行渲染骨骼。
因此,本文将尝试从系统侧(尤其是内核暴露的 sysfs / cgroup 等)观察“哪些进程在使用 GPU”,并与“系统认为这个进程属于哪个应用/UID”做交叉验证,从而找出可疑进程。
本文以一段 Android/Linux 环境下的示例代码为线索,讲清它在做什么、为什么这样做,以及有哪些坑和改进方向。
整体思路概览
这段代码的核心是一个“交叉校验”:
- 从 GPU 驱动的 sysfs 节点枚举“疑似使用 GPU 的进程 pid”
典型路径:
/sys/class/kgsl/kgsl/pagetables/<pid> 这里的
kgsl 是高通 Adreno GPU 常见的内核驱动接口。- 从 cgroup 的 uid 目录枚举系统中存在的 uid
典型路径:
/sys/fs/cgroup/uid_<uid>/pid_<pid> Android 会把进程按 uid 组织在 cgroup 里(不同 ROM/版本会略有差异)。
- 对每个 GPU pid,判断它能否在任意 uid 的 cgroup 目录下找到归属
- 如果找不到归属:说明这个 pid 在 cgroup 视角里“很异常”(或你的枚举逻辑不完整)。
- 然后再做一次“时间戳差异”检查:用
stat()拿文件创建/变更时间,判断是否与基准时间差异过大,作为进一步可疑信号。
最终,它会把命中的 pid 打印出来,作为“疑似异常渲染/异常 GPU 使用”的候选目标。
代码逐段解读
下面是原始示例:
1) 枚举 GPU pagetables 目录下的 pid
/sys/class/kgsl/kgsl/pagetables/下的子项通常以 pid 命名(并非所有设备/内核都一致)。
- 通过
access(path, F_OK)判断这个路径是否存在:存在就认为该 pid “有 GPU pagetable 记录”,即“可能使用过 GPU/图形上下文”。
这里的安全含义:
如果某个进程在做渲染/图形相关操作(例如 OpenGL/Vulkan/SurfaceFlinger 相关),有机会在 KGSL 的 sysfs 接口里留下对应条目。
2) 枚举 cgroup 下的 uid
这一步的思路是:
- Android 常把每个应用(UID)放在一个
uid_<uid>目录下。
- 只要目录存在,就把 uid 收集起来。
注意:
0..100000是一个非常粗暴的上界,会导致大量系统调用(性能/耗电风险)。
- 不同 Android 版本的 cgroup 结构可能不同(cgroup v1/v2、挂载点、目录命名、层级等都可能变化)。
3) 交叉验证:GPU pid 是否能在任意 uid 目录下找到归属
- 如果
uid_<uid>/pid_<pid>存在,则认为该 pid 在 cgroup 的“uid 视角”里是正常可归属的。
- 如果遍历所有 uid 都找不到这个 pid 的归属,则
normal=false,进入“异常处理”。
这里的核心假设:
“正常进程”应该在 cgroup 的 uid 目录里能被定位到;如果 GPU sysfs 里出现了 pid,但 cgroup 里找不到归属,那就值得怀疑。
