fuqiuluo’s blog

记录美好生活

技术分享

游戏安全之GPU渲染检测

#竞赛#Linux#作弊
type
Post
status
Published
date
Apr 16, 2025
slug
summary
tags
竞赛
Linux
作弊
category
技术分享
icon
password

背景:为什么要做“渲染检测”

在移动端游戏安全对抗里,“外挂在不在渲染”是一个很常见的判据:
  • 正常游戏进程会创建图形上下文、提交渲染任务,因此在 GPU/图形驱动相关的内核接口里会留下痕迹。
  • 某些作弊/分析进程不会注入目标进程,以降低被发现的概率,但是他们仍旧会调用GPU进行渲染骨骼。
因此,本文将尝试从系统侧(尤其是内核暴露的 sysfs / cgroup 等)观察“哪些进程在使用 GPU”,并与“系统认为这个进程属于哪个应用/UID”做交叉验证,从而找出可疑进程。
本文以一段 Android/Linux 环境下的示例代码为线索,讲清它在做什么、为什么这样做,以及有哪些坑和改进方向。

整体思路概览

这段代码的核心是一个“交叉校验”:
  1. 从 GPU 驱动的 sysfs 节点枚举“疑似使用 GPU 的进程 pid”
    1. 典型路径:/sys/class/kgsl/kgsl/pagetables/<pid>
      这里的 kgsl 是高通 Adreno GPU 常见的内核驱动接口。
  1. 从 cgroup 的 uid 目录枚举系统中存在的 uid
    1. 典型路径:/sys/fs/cgroup/uid_<uid>/pid_<pid>
      Android 会把进程按 uid 组织在 cgroup 里(不同 ROM/版本会略有差异)。
  1. 对每个 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 里找不到归属,那就值得怀疑。
Loading...