Overt是一个专业的Android设备安全检测工具,通过多维度收集和分析系统信息来检测设备是否被Root、被调试工具注入或存在其他安全风险。项目采用模块化架构设计,将不同功能分散到独立的模块中,便于维护和扩展。所有代码都经过详细注释,确保代码的可读性和可维护性。
- 多维度安全检测: 涵盖Root检测、调试工具检测、系统完整性检测等
- 模块化设计: 清晰的模块分离,便于维护和功能扩展
- 安全通信: 基于mbedTLS的HTTPS通信,支持证书固定验证
- 非标准API支持: 可切换使用标准API或非标准API,绕过libc层直接进行系统调用
项目采用多模块架构,包含app(主应用)、zcore(核心功能库)、zinfo(信息收集)、zconfig(配置管理)、zlog(日志)、zstd(标准库工具)、zlibc(系统调用封装)等模块。采用分层依赖架构,从配置管理到任务调度共分6个依赖等级。
-
文件系统检测:
- 遍历常见Root文件路径(如
/system/bin/su、/system/xbin/su等) - 检查文件是否存在,存在则判定为Root设备
- 检测Root管理应用(SuperSU、Magisk Manager等)的安装
- 遍历常见Root文件路径(如
-
系统属性检测:
- 检查
ro.secure、ro.debuggable等关键系统属性 - 验证属性值是否符合预期,异常值表示可能被Root
- 检查
-
挂载点检测:
- 分析
/proc/mounts文件,检测异常挂载点 - 检测overlay文件系统挂载,这是Magisk等Root框架的常见特征
- 分析
-
类加载器遍历:
- 通过JVM接口获取所有已加载的类加载器
- 将类加载器转换为字符串表示
-
特征匹配:
- 检测
LspModuleClassLoader等LSPosed框架的类加载器 - 检测
InMemoryDexClassLoader等内存动态加载的类加载器 - 这些类加载器通常由Hook框架注入
- 检测
-
类名检测:
- 遍历所有已加载的类名
- 匹配黑名单类名(如
lsposed、XposedBridge等) - 发现可疑类名则判定为存在Hook框架
-
系统调用时序分析:
- 绑定线程到特定CPU核心,确保测量稳定性
- 使用ARM64虚拟计数器(
cntvct_el0寄存器)获取高精度时间戳 - 执行大量系统调用(如
faccessat、fchownat)并记录执行时间
-
异常检测:
- 正常情况下,
faccessat的执行速度应该快于fchownat - 如果
faccessat大量慢于fchownat,说明存在Hook框架拦截 - Hook框架会增加系统调用的执行时间,导致时序异常
- 正常情况下,
-
阈值判定:
- 统计异常次数,超过阈值(如7000次)则判定为环境异常
- 这种方法可以检测到基于系统调用Hook的调试工具
-
本地时间获取: 使用标准时间函数获取系统当前时间
-
启动时间检测:
- 通过系统调用获取系统启动时间
- 分析
/proc/mounts中文件系统的最早创建时间 - 启动时间过短可能表示设备刚重启或时间被篡改
-
远程时间验证:
- 通过HTTPS请求获取远程服务器时间
- 使用证书固定验证确保通信安全
- 比较本地时间和远程时间,差异过大则判定为时间被篡改
-
maps文件解析:
- 解析
/proc/self/maps文件,获取进程内存映射信息 - 分析关键系统库(如
libart.so、libc.so)的映射情况
- 解析
-
映射数量检测:
- 正常情况下,系统库应该有固定数量的内存段(通常为4个)
- 映射数量异常可能表示库被篡改或Hook
-
权限检测:
- 检查内存段的权限标志(如
r--p、r-xp、rw-p) - 权限异常可能表示内存被修改或Hook框架注入
- 检查内存段的权限标志(如
-
内容检测:
- 读取关键文件(如
base.odex)的二进制内容 - 搜索可疑字符串(如
--inline-max-code-units=0) - 发现可疑内容则判定为存在Hook框架
- 读取关键文件(如
-
进程状态分析:
- 解析
/proc/self/status文件,获取进程状态信息 - 检测进程的TracerPid,非零值表示进程被调试
- 解析
-
任务信息检测:
- 分析
/proc/self/task目录,获取所有线程信息 - 检测可疑线程名(如
gmain、pool-frida等Frida相关线程)
- 分析
-
内存映射分析:
- 检测内存中映射的可疑库文件
- 识别调试工具和Hook框架的特征库
-
HTTPS连接建立:
- 使用mbedTLS建立HTTPS连接
- 获取服务器证书链
-
证书指纹验证:
- 计算证书的SHA256指纹
- 与预置的证书指纹进行比较
- 指纹不匹配则判定为中间人攻击或证书被篡改
-
证书固定:
- 实现证书固定机制,只信任特定的证书
- 防止中间人攻击和证书伪造
-
Android ID获取:
- 通过JNI调用Android Settings.Secure API获取android_id
- Android ID是设备唯一标识符,用于设备识别
-
存储指纹生成:
- 使用
statfs64系统调用获取存储文件系统信息 - 提取文件系统类型、块大小、块数量、文件数量、文件系统ID等特征
- 拼接生成唯一的存储指纹字符串
- 使用
-
DRM ID获取:
- 使用Android MediaDrm API获取Widevine DRM设备唯一ID
- 将32字节的DRM ID压缩为16个十六进制字符
- DRM ID为空可能表示设备DRM功能异常或被禁用
-
共享库路径遍历:
- 通过动态链接器获取所有已加载共享库的路径列表
- 遍历所有库路径,检测可疑库文件
-
黑名单库检测:
- 检测LSPosed相关库(包含"lsposed"字符串)
- 检测Frida相关库(包含"frida"字符串)
- 这些库的存在通常表明Hook框架已注入
-
CRC校验和检测:
- 对关键系统库(如
libc.so、libart.so、libinput.so)进行CRC校验 - 比较运行时库的CRC值与预期值
- CRC不匹配表示库文件被篡改或Hook
- 对关键系统库(如
-
KeyStore认证证书获取:
- 通过Android KeyStore API生成密钥对
- 设置认证挑战(Attestation Challenge)
- 获取包含TEE认证信息的X.509证书
-
证书解析:
- 使用OpenSSL解析X.509证书
- 提取TEE认证扩展(TEE Attestation Extension)
- 解析认证记录(Attestation Record)中的授权列表
-
安全状态检测:
- 检查设备锁定状态(device_locked),未锁定则判定为不安全
- 检查验证启动状态(verified_boot_state),非已验证状态则判定为不安全
- 检查RootOfTrust信息,验证启动密钥和状态
-
Context方式检测:
- 通过PackageManager.getApplicationInfo检测应用是否安装
- 通过PackageManager.getLaunchIntentForPackage作为备用检测方法
- 检测Root管理应用(如SuperSU、Magisk Manager等)
-
路径方式检测:
- 检查
/data/data、/data/user/0、/data/user_de/0等应用数据目录 - 检查
/storage/emulated/0/Android/data外部存储目录 - 应用数据目录存在则判定为应用已安装
- 检查
-
越权检测:
- 使用路径漏洞检测(如
/sdcard/android/\u200bdata/) - 使用Shell命令越权检测
- 这些方法可以绕过某些检测机制
- 使用路径漏洞检测(如
-
充电状态检测:
- 通过注册BatteryManager广播接收器获取电池状态
- 检测设备是否正在充电或已充满
- 充电状态异常可能表示设备环境异常
-
安装器名称检测:
- 通过PackageManager获取应用的安装器包名
- 检测是否通过可疑安装器安装(如Root管理应用)
- 异常安装器可能表示应用被恶意修改
-
属性遍历:
- 使用
__system_property_foreach遍历所有系统属性 - 解析属性内部结构,提取属性名、值和序列号
- 使用
-
关键属性验证:
- 检查
ro.secure属性,应为"1"表示安全模式 - 检查
ro.debuggable属性,应为"0"表示不可调试 - 检查
ro.build.tags属性,应为"release-keys" - 属性值异常表示系统可能被修改或Root
- 检查
-
序列号分析:
- 解析属性序列号的dirty标志、版本号和值长度
- 序列号异常可能表示属性被动态修改
-
APK路径获取:
- 通过
dladdr获取当前库文件路径 - 使用正则表达式提取应用特定目录路径
- 构建
base.apk的完整路径
- 通过
-
ZIP文件解析:
- 使用minizip库解析APK文件(APK本质是ZIP格式)
- 遍历ZIP文件中的条目,查找META-INF目录下的.RSA签名文件
-
签名提取和验证:
- 提取.RSA文件的二进制内容
- 计算签名文件的SHA256哈希值
- 验证签名文件是否存在和有效
-
端口连接检测:
- 创建TCP socket并尝试连接到指定端口
- 使用非阻塞模式,设置200ms超时
- 连接成功则判定为端口被占用
-
可疑端口检测:
- 检测调试工具常用端口(如Frida默认端口27042)
- 检测Root框架常用端口
- 端口被占用可能表示调试工具或Root框架正在运行
-
错误处理:
- 处理连接失败、超时等异常情况
- 使用
select系统调用等待连接结果 - 检查socket错误状态确定连接是否成功
-
UDP广播机制:
- 启动UDP广播发送器,向端口7476发送"overt"消息
- 启动UDP广播监听器,监听端口7476接收响应
- 启动本地IP监控,获取本机网络信息
-
设备发现:
- 接收UDP广播响应,记录发送方的IP地址
- 将检测到的Overt设备标记为警告级别
- 用于检测同一网络中的其他Overt设备
-
日志遍历:
- 遍历指定PID范围(1500-2000),检查每个进程的日志记录
- 使用
logcat -d命令获取系统日志
-
可疑记录检测:
- 搜索日志中包含
avc(SELinux审计日志)和u:r:su:s0(Root权限上下文)的记录 - 这些记录通常由Zygisk等Root框架产生
- 发现可疑记录则判定为存在Root框架
- 搜索日志中包含
-
进程路径验证:
- 检查对应PID的进程路径是否存在
- 确保检测的进程确实存在
-
Binder通信机制:
- 通过共享内存和Binder IPC与隔离进程通信
- 发送"get_isoloated_process_info"消息请求进程信息
-
进程信息获取:
- 隔离进程执行进程信息检测(调用
get_proc_info) - 将检测结果序列化为JSON格式返回
- 主进程解析JSON响应,获取隔离进程的检测结果
- 隔离进程执行进程信息检测(调用
-
跨进程检测优势:
- 隔离进程运行在独立进程空间,可能检测到主进程无法检测的异常
- 通过Binder通信实现跨进程信息共享
-
传感器管理器:
- 使用
zSensorManager单例管理传感器检测 - 获取设备上所有可用的传感器
- 使用
-
风险评分计算:
- 检测传感器FIFO是否为空(可能表示传感器被禁用)
- 检测唤醒传感器数量是否过少
- 检测传感器延迟是否过于均匀(可能表示数据被伪造)
- 检测传感器总数是否过低
-
风险等级判定:
- 根据风险评分计算风险等级
- 评分超过60为错误级别,否则为警告级别
- 通过风险位标志标识具体的风险类型
- Android Gradle Plugin: 8.3.0
- Gradle版本: 8.4
- compileSdk: 34
- targetSdk: 34
- minSdk: 23
- ABI支持: arm64-v8a
- Java版本: 17
- NDK版本: 21.1.6352462
- CMake版本: 3.22.1
- mbedTLS: 用于加密和安全通信
# 确保已安装Android SDK 34和NDK 21.1.6352462
# 确保已安装CMake 3.22.1或更高版本
# 确保已安装Java 17
# 确保已安装Gradle 8.4# 编译所有模块
./gradlew assembleDebug
# 编译特定模块
./gradlew :app:assembleDebug
./gradlew :zcore:assembleDebug
./gradlew :zinfo:assembleDebug
# 清理项目
./gradlew clean在zconfig/src/main/cpp/zConfig.h中修改ZCONFIG_ENABLE_NONSTD_API宏:
- 启用非标准API:
#define ZCONFIG_ENABLE_NONSTD_API 1 - 使用标准API:
#define ZCONFIG_ENABLE_NONSTD_API 0
修改后重新编译项目即可生效。
- Android Key Attestation
- Android Keystore System
- X.509 Certificate Structure
- ASN.1 Encoding Rules
- https://android.googlesource.com/platform/ndk
- https://github.com/openjdk/jdk8u.git
- https://github.com/vvb2060/KeyAttestation.git
注意: 本项目仅用于安全研究和教育目的,请遵守相关法律法规,不得用于非法用途。