Frida
进程与端口:
- 默认端口:
27042(Frida Server 通信端口),可能被修改为其他端口(如6666、9999)。 - 进程名:
- 典型进程:
frida-server、frida-helper(Android)、frida-agent(嵌入式模式)。 - 可能伪装为普通进程名(如
com.android.settings)。
- 典型进程:
文件痕迹:
- 二进制文件:
- 常见路径:
/data/local/tmp/frida-server、/data/local/tmp/re.frida.server。 - 嵌入式模式:应用内集成
frida-gadget.so(路径如/data/app/<包名>/lib/arm64/libfrida-gadget.so)。
- 常见路径:
- 动态库:
- 加载
libfrida.so、libfrida-gumjs.so或libagent.so。 - 可能被重命名(如
libhello.so)以绕过静态检测。
- 加载
行为特征:
- 代码注入:
- 使用
ptrace或LD_PRELOAD注入代码,劫持关键函数(如open、fopen)。 - 修改内存页权限(
mprotect或mmap)以动态执行代码。
- 使用
- 内存特征:
- 内存中存在字符串
frida-gadget、frida:rpc、gum-js-loop、FridaScriptEngine。 - 函数指针表(如
GOT/PLT)被篡改,指向 Frida 的代理代码。
- 内存中存在字符串
- Hook 检测:
- 函数完整性校验:
- 检查关键函数(如
ptrace、open)的前几条指令是否被修改(如JMP指令)。 - 对比函数代码的哈希值(如
.text段的 SHA256)与预期是否一致。
- 检查关键函数(如
- 内存映射异常:
- 检测内存中是否存在可写且可执行的页(
rwx权限),常见于 Frida 的代码注入。
- 检测内存中是否存在可写且可执行的页(
- Inline Hook 检测:
- 扫描内存中
FAR JUMP(远跳转指令)或trampoline代码片段。
- 扫描内存中
- 函数完整性校验:
检测方法:
-
静态检测:
- 扫描 APK 或二进制文件中的
frida相关字符串、库文件或端口配置。 - 检查
AndroidManifest.xml中是否声明可疑权限(如ptrace、注入)。
- 扫描 APK 或二进制文件中的
-
动态检测:
- 进程与线程扫描:
- 遍历
/proc/<pid>/cmdline和/proc/<pid>/status,查找frida相关进程或线程名。 - 检测异常线程(如
pool-frida、gmain)。
- 遍历
- 内存映射分析:
- 检查
/proc/self/maps或/proc/<pid>/maps中是否存在frida、gadget或匿名可执行内存段。
- 检查
- 主动探测:
- 尝试连接默认端口(
127.0.0.1:27042),若返回{"type":"error"}则可能存在 Frida。 - 调用
frida_get_uid()或frida_enumerate_devices()等未公开函数,若未崩溃则可能未注入。
- 尝试连接默认端口(
- 进程与线程扫描:
-
Hook 防御:
- 反 Hook 技术:
- 使用
syscall直接调用系统函数(绕过libc的 Hook)。 - 在敏感函数入口插入
SIGTRAP或INT3指令,触发断点异常。
- 使用
- 完整性校验:
- 使用
dl_iterate_phdr()遍历已加载模块,检查是否有未签名的库(如libfrida)。 - 实时校验关键函数代码(如
memcmp对比.text段内容)。
- 使用
- 反 Hook 技术:
-
对抗隐藏技术:
- 检测重命名进程:
- 监控进程的父进程和子进程关系(Frida 可能由
adb或shell启动)。
- 监控进程的父进程和子进程关系(Frida 可能由
- 检测端口复用:
- 使用
netstat或/proc/net/tcp分析本地端口通信模式(Frida 通信流量有固定特征)。
- 使用
- 检测重命名进程:
Root
- 核心用途:获取 Android 系统的最高权限(
root)。 - 特征:
- 文件系统痕迹:
- 存在
su二进制文件(路径如/system/bin/su,/system/xbin/su)。 - Root 管理应用(如 SuperSU、Magisk 等)的安装痕迹。
- 存在
- 系统属性:
ro.build.tags可能包含test-keys(非官方系统签名)。ro.debuggable=1(系统允许调试)。
- 行为特征:
/system分区被挂载为可写(正常应为只读)。- SELinux 状态为
Permissive或关闭。
- 检测方法:
- 检查
su命令是否存在或尝试执行su -v。 - 验证系统分区的哈希或只读属性(如
mount | grep /system)。 - 使用
SafetyNet API(已废弃)或Play Integrity API(Google 官方检测)。
- 检查
- 文件系统痕迹:
Xposed 框架
- 核心用途:通过加载模块在系统层面 Hook 应用和系统方法。
- 特征:
- 文件痕迹:
- 安装 Xposed 管理应用(如
Xposed Installer)。 - 存在 Xposed 库文件(如
libxposed_art.so)。
- 安装 Xposed 管理应用(如
- 运行时特征:
- 应用进程加载 Xposed 模块(如
XposedBridge.jar)。 - 系统类(如
java.lang.ClassLoader)被修改。
- 应用进程加载 Xposed 模块(如
- 检测方法:
- 检查
XposedHelper类或de.robv.android.xposed.XposedBridge是否存在。 - 遍历已安装应用列表,寻找 Xposed 模块包名(如
de.robv.android.xposed.installer)。 - 监控方法调用栈中是否包含 Xposed 相关调用(如
XposedBridge.handleHookedMethod)。
- 检查
- 文件痕迹:
8poll
应用模拟器 root 环境下会跳出 toast 警告并自动退出

尝试 hook toast
包名 com.miniclip.eightballpool
Java.perform(function() {
var Toast = Java.use("android.widget.Toast");
Toast.makeText.overload('android.content.Context', 'java.lang.CharSequence', 'int').implementation = function(context: any, text: any, duration: any) {
console.log("[!] Toast.makeText called with text: " + text);
var stackTrace = Java.use("java.lang.Exception").$new().getStackTrace();
for (var i = 0; i < stackTrace.length; i++) {
console.log("Stack Trace: " + stackTrace[i].toString());
}
return this.makeText(context, text, duration);
};
Toast.show.implementation = function() {
console.log("[!] Toast.show called");
var stackTrace = Java.use("java.lang.Exception").$new().getStackTrace();
for (var i = 0; i < stackTrace.length; i++) {
console.log("Stack Trace: " + stackTrace[i].toString());
}
// 调用原始 show 方法
return this.show();
};
});
从堆栈追踪来看,InjectedActivity 类中的 showToast 方法在 handleExitToast 中被调用。
因此,这个 Toast 是通过 InjectedActivity 类中的 handleExitToast 方法间接调用的。如果你想要更深入地分析 Toast 被调用的具体逻辑,应该查看 InjectedActivity 中 showToast 和 handleExitToast 方法的实现。
runtime.loading.InjectedActivity.showPopup 加载了 libloader
通过库可以跟踪到 io.adjoe.protection.DeviceUtils 调用了可疑的检测 emulator 的方法

应该是通过 org.json.JSONObject 这个 Mozilla 的库来传递设备当前的信息。然后通过读取 JSON 来判断异常情况。
可以 hook 结果看看,然后看看能不能改变值绕过去
试一下 toString() 方法:
竟然 hook 不到,我研究一下整个调用逻辑链看看,是不是我搞错了(还没到这步就挂了)