安卓端总结监测总结
Root检测
BL锁检测
- 系统属性(Properties)检测
这是最简单但也最容易被伪装的层级。
ro.boot.flash.locked: 值为1表示锁定,0表示解锁。ro.boot.verifiedbootstate:green: 锁定且签名验证通过。orange: 已解锁(最常见的检测点)。yellow: 加载了自定义证书。red: 验证失败。
ro.secureboot.devicelock: 部分厂商(如华为、小米)自定义的锁定状态属性。
- 内核启动参数 (
/proc/cmdline)
系统启动时,Bootloader 会将硬件状态传递给内核。
- 在
/proc/cmdline中,通常包含androidboot.verifiedbootstate=orange或androidboot.flash.locked=0。 - 关键点:由于
/proc/cmdline是内核导出的只读信息,传统的setprop无法修改它。
- 安全环境校验 (TEE / Keymaster)
这是目前最主流的硬件级检测:
- App 会生成一个密钥对,并要求 TEE(可信执行环境)对该密钥进行 Attestation(证书颁发)。
- TEE 会在证书中包含硬件状态信息。如果 BL 已解锁,TEE 签发的证书里会明确标注
SecurityLevel为Software或标注 Bootloader 状态。 - 不可伪装性:因为证书是由 TEE 内置的私钥签名的,外部无法篡改。
- Play Integrity API (原 SafetyNet)
Google 的云端校验方案:
- MEETS_DEVICE_INTEGRITY: 检查基本完整性(是否 Root/解锁)。
- MEETS_STRONG_INTEGRITY: 终极杀招。它要求硬件级的 TEE 验证,只要 BL 解锁,绝无可能通过此项。
magisk
/proc/self/mounts查看挂载信息里是否有magisk的痕迹
kernelsu检测
分别收集__NR_faccessat和__NR_fchownat的执行时间,kernelsu会对这些函数进行hook

hook/调试检测
Frida端口扫描
Frida 在默认模式下运行(例如通过 frida-server 模式)时,会在设备上启动一个服务端,并默认监听 27042 和 27043 端口,用于与 PC 端的 Frida 客户端进行通信。
Maps记录检测
读取/proc/self/maps,检测程序是否加载了frida相关的库,最常见的就是frida-agent.so。
为了对应魔改,还会检测是否存在未命名且具有 r-xp(可读可执行)权限的大段内存
fd检测
遍历 /proc/self/fd/ 目录,并通过 readlink 获取每个 fd 指向的真实目标。
检测是否存在指向 Frida 特有文件的描述符,例如包含 linjector 关键字的路径,或者异常的 Socket 链接(用于与 frida-server 交互)。
Trace状态检查
读取 /proc/self/status 文件,检查其中的 TracerPid 字段。
在正常运行状态下,TracerPid 的值应为 0。如果该值大于 0,说明当前 App 正在被另一个进程(很可能就是 Frida、调试器或注入工具)附加和调试。
父子进程检测
fork出一个子进程,然后attach,像frida的attach模式,调试器附加,都没办法再生效了。
线程检测
App 遍历 /proc/self/task/ 目录(或者 /proc/self/status 文件),读取各个线程的名称(通过读取 comm 或 status 文件)。
寻找特定的特征线程名,例如:gmain、gdbus、gum-js-loop、pool-frida 等。
1 | 2026-03-04 13:03:09.451 11077-11077 FridaDetect twogoat.checker2 E Thread Detection: gmain |
内存校验
通常采用crc校验等对一段代码段校验完整性,或者检查函数头是否有inline hook的痕迹
为了防止被stackplz等工具检测到,可以使用process_vm_readv系统调用来把内存复制到缓冲区
ArtMethod检测
通过解析java方法的access_flags和entry_point_from_quick_compiled_code是否遭到篡改检测
多线程检测
由于上面很多检测都需要实时检测,不可避免的要用到多线程,因此用pthread_create是最常见的做法,但也是容易直接被替换为一个空函数直接逃过所有检测
因此现在很常见的做法是使用更底层的clone函数创建线程
或者在线程里用系统调用实时更新一个全局变量的心跳,在另一边,不容易被发现的地方,比如在godot游戏引擎中,创建一个实时刷新的函数,检测自己获取的时间与心跳的差值,同时可以防止反调试
这里还有思路就是多线程一直解锁,业务层一直上锁,但是这里不能用互斥锁,因为规定一个mutex不能在当前线程被lock,在另一个线程unlock,不允许跨线程操作
这里使用了信号量,敢替换sem_wait直接阻塞
1 |
|
不过要注意sem_wait会阻塞当前线程,所以最好不要在主线程阻塞,不然整个程序就真的卡死了
1 | void registerButton() |
流量检测
frida server与agent之间通过dbus协议传输,server与rpc之间通过websocket传输,经过抓包发现都是明文且特征明显,所以可以hook相关的网络协议函数,进行侦测
Trampoline特征查找
Frida生成的匿名函数,前面都是固定的机器码,是很多对寄存器的操作,可以直接在一些可疑的匿名函数段尝试暴力匹配
- 标题: 安卓端总结监测总结
- 作者: 两只羊
- 创建于 : 2026-05-06 11:27:39
- 更新于 : 2026-05-12 10:44:56
- 链接: https://twogoat.github.io/2026/05/06/安卓端总结监测总结/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。