Frida

进程与端口

  • 默认端口27042(Frida Server 通信端口),可能被修改为其他端口(如 66669999)。
  • 进程名
    • 典型进程:frida-serverfrida-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.solibfrida-gumjs.solibagent.so
    • 可能被重命名(如 libhello.so)以绕过静态检测。

行为特征

  • 代码注入
    • 使用 ptraceLD_PRELOAD 注入代码,劫持关键函数(如 openfopen)。
    • 修改内存页权限(mprotectmmap)以动态执行代码。
  • 内存特征
    • 内存中存在字符串 frida-gadgetfrida:rpcgum-js-loopFridaScriptEngine
    • 函数指针表(如 GOT/PLT)被篡改,指向 Frida 的代理代码。
  • Hook 检测
    • 函数完整性校验
      • 检查关键函数(如 ptraceopen)的前几条指令是否被修改(如 JMP 指令)。
      • 对比函数代码的哈希值(如 .text 段的 SHA256)与预期是否一致。
    • 内存映射异常
      • 检测内存中是否存在可写且可执行的页(rwx 权限),常见于 Frida 的代码注入。
    • Inline Hook 检测
      • 扫描内存中 FAR JUMP(远跳转指令)或 trampoline 代码片段。

检测方法

  1. 静态检测

    • 扫描 APK 或二进制文件中的 frida 相关字符串、库文件或端口配置。
    • 检查 AndroidManifest.xml 中是否声明可疑权限(如 ptrace注入)。
  2. 动态检测

    • 进程与线程扫描
      • 遍历 /proc/<pid>/cmdline/proc/<pid>/status,查找 frida 相关进程或线程名。
      • 检测异常线程(如 pool-fridagmain)。
    • 内存映射分析
      • 检查 /proc/self/maps/proc/<pid>/maps 中是否存在 fridagadget 或匿名可执行内存段。
    • 主动探测
      • 尝试连接默认端口(127.0.0.1:27042),若返回 {"type":"error"} 则可能存在 Frida。
      • 调用 frida_get_uid()frida_enumerate_devices() 等未公开函数,若未崩溃则可能未注入。
  3. Hook 防御

    • 反 Hook 技术
      • 使用 syscall 直接调用系统函数(绕过 libc 的 Hook)。
      • 在敏感函数入口插入 SIGTRAPINT3 指令,触发断点异常。
    • 完整性校验
      • 使用 dl_iterate_phdr() 遍历已加载模块,检查是否有未签名的库(如 libfrida)。
      • 实时校验关键函数代码(如 memcmp 对比 .text 段内容)。
  4. 对抗隐藏技术

    • 检测重命名进程
      • 监控进程的父进程和子进程关系(Frida 可能由 adbshell 启动)。
    • 检测端口复用
      • 使用 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 模块(如 XposedBridge.jar)。
      • 系统类(如 java.lang.ClassLoader)被修改。
    • 检测方法
      • 检查 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 被调用的具体逻辑,应该查看 InjectedActivityshowToasthandleExitToast 方法的实现。

runtime.loading.InjectedActivity.showPopup 加载了 libloader

通过库可以跟踪到 io.adjoe.protection.DeviceUtils 调用了可疑的检测 emulator 的方法

应该是通过 org.json.JSONObject 这个 Mozilla 的库来传递设备当前的信息。然后通过读取 JSON 来判断异常情况。

可以 hook 结果看看,然后看看能不能改变值绕过去

试一下 toString() 方法:

竟然 hook 不到,我研究一下整个调用逻辑链看看,是不是我搞错了(还没到这步就挂了)