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 代码片段。

检测方法:

  1. 静态检测:

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

    • 进程与线程扫描:
      • 遍历 /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() 等未公开函数,若未崩溃则可能未注入。
  3. Hook 防御:

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

    • 检测重命名进程:
      • 监控进程的父进程和子进程关系(Frida 可能由 adb 或 shell 启动)。
    • 检测端口复用:
      • 使用 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 被调用的具体逻辑,应该查看 InjectedActivity 中 showToast 和 handleExitToast 方法的实现。

runtime.loading.InjectedActivity.showPopup 加载了 libloader

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

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

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

试一下 toString() 方法:

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