论坛首页 蓝队防御建设区 阅读主题

[原创]Frida 常见检测与绕过

242 浏览 10 回复
#1 楼主 2026-06-01 21:09:11
这是最基础也是最常见的检测手段。由于绝大多数 Frida 教程都指导用户将服务端文件命名为 frida-server​ 并放置在 /data/local/tmp/ 目录下,App 的防护机制会针对这些“标准特征”进行扫描。防护代码通常会在 App 启动时执行以下检查:App 会尝试访问 Android 系统中的常见临时目录,查找是否存在包含 frida 关键字的文件。代码示例 (伪代码) :App 可以通过 Shell 命令或读取系统文件来获取当前运行的所有进程列表,并匹配黑名单。扫描方式:执行 ps -A 查看进程状态。​敏感关键字​:frida-server​, frida-helper​, frida-launcher​代码示例 (伪代码) :针对上述特征检测,最直接有效的方法就是 “改名” 。这是最简单的一步。将 frida-server 重命名为类似系统进程的名字,既能避开文件扫描,启动后的进程名也会随之改变,从而避开进程扫描。​操作步骤:有些深度检测不仅仅匹配文件名,还会扫描二进制文件内部的字符串特征(如 frida:rpc​ 字符串)。
此时,单纯重命名文件无效。你需要使用 ​HLuda(魔改版 Frida)。Frida 在运行时需要开启 TCP 端口与电脑端进行数据传输。如果不加配置,Frida 会默认绑定特定的特征端口,这成为了 App 检测的重要依据。Frida 服务端启动后,默认会监听以下两个端口:防护代码通常采用以下方式进行探测:App 可以执行 netstat​ 命令,查看当前系统是否有名为 0.0.0.0:27042​ 或 127.0.0.1:27042 的监听状态。绕过的核心思想是 ​ “避开默认” 。只要我们不使用 27042 端口,上述针对固定端口的扫描就会失效。在手机端启动 frida-server​ 时,使用 -l​ (listen) 参数指定一个随机的非标准端口(例如 8888​ 或 6666)。修改端口后,电脑端的 Frida 客户端不会自动识别,必须手动进行端口转发或指定连接地址。方式 A:通过 USB 转发 (推荐)
我们需要将电脑的 8888​ 端口转发到手机的 8888 端口。方式 B:通过 WiFi 连接
如果手机和电脑在同一局域网,可以直接指定手机 IP。这是 Android Native 层反调试最经典的手段之一。Linux/Android 内核规定:​同一个进程同时只能被一个调试器(Tracer)附加。​Frida 的工作原理​:Frida 本质上也是一个调试器,它需要通过 ptrace 系统调用附加(Attach)到目标 App 进程上才能进行 Hook。​App 的防御手段​:App 在启动的极早期(通常在 .init_array​ 或 JNI_OnLoad​ 中),主动调用 ptrace(PTRACE_TRACEME, 0, 0, 0) 自己附加自己。​冲突结果:​代码示例 (C/C++) :针对 ptrace​ 占坑,单纯的“Attach 模式”是必死的。我们需要利用 Frida 的 Spawn 模式 抢在 App 运行代码前介入,并修改 App 的检测逻辑。Spawn 模式 (-f) 会由 Zygote 进程 fork 出目标 App,并在 App 执行任何自己的代码(包括反调试代码)之前将 Frida 的 Gadget/Agent 注入进去。这给了我们一个“时间差”:Frida 先进去了,现在轮到 Frida 掌控局面。仅仅进入是不够的。如果 Frida 保持附加状态,App 随后的 ptrace​ 调用会失败,App 依然会发现并退出。
​根本的解决办法是​:Hook libc.so​ 中的 ptrace​ 函数,拦截 App 的调用,直接返回 0(假装成功),并且不要执行真正的 ptrace 系统调用。示例脚本:Frida 的客户端与服务端通信基于 D-Bus 协议(一种进程间通信/RPC 机制)。即使我们将 Frida 服务端改名并迁移目录,其通信协议的特征(尤其是握手阶段)依然是固定的。App 可以遍历本地所有开放的 TCP 端口,并尝试建立 Socket 连接。一旦连接成功,App 会发送 D-Bus 协议特定的握手消息。如果服务端响应了特定的 D-Bus 关键字(如 REJECT),则可认定该端口运行着 Frida。​检测代码示例 (伪代码) :这是您提到的方法。原理是拦截 App 在处理网络响应时的比较逻辑。当 App 拿收到的数据去匹配 "REJECT" 时,我们欺骗它说“没匹配上”。注意:strcmp​ 和 strstr​ 是系统底层极其高频调用的函数。直接 Hook 会导致 App 巨卡无比甚至崩溃,必须加严格的过滤条件。相比于在运行时 Hook 极不稳定的 strstr,最彻底的办法是从源码层面消除特征。​HLuda(或其他去特征版本)在编译 Frida 时做了如下修改:使用此类版本后,App 发送探测包收到的将不再是标准的 REJECT,从而直接绕过检测机制,无需编写任何 Hook 脚本。在 Linux/Android 系统中,一切皆文件。/proc/pid/fd/ 目录包含了当前进程打开的所有文件描述符(File Descriptors)。App 通过遍历该目录,可以获知进程加载了哪些文件、建立了哪些 Socket 连接。App 遍历 /proc/self/fd​ 目录下的所有文件,并使用 readlink​ 读取符号链接指向的​真实路径。​相关命令​:ls -l /proc/self/fd​ 或 readlink -f /proc/self/fd/<id>检测代码示例 (伪代码) :如果 Frida 注入成功,该目录下可能会出现指向以下路径的链接:​传统特征 (旧版 Frida) :在 高版本 Frida (>=16) 时:检查 FD 已经基本无法检测 Frida。在 Android 10+ 中,Google 对 memfd 的名称做了更严格的匿名化,Frida 使用的 memfd 不再暴露名称。无论特征如何变化,检测的核心动作都是调用 readlink​ 或 readlinkat​ 系统函数。
​核心思路​:Hook 这两个函数,当 App 试图读取的文件描述符指向包含 frida​、gum​ 或 memfd​ 的路径时,将其替换为合法的系统路径(如 /dev/null​ 或 libc.so)。在 Android (Linux) 系统中,进程的每一个线程在 /proc/pid/task/ 目录下都有一个对应的子目录(目录名为线程 ID)。App 可以遍历该目录,读取每个线程的 ​status​​ 或 ​comm​ 文件,获取线程名称。由于 Frida 依赖 GLib 库,运行时会创建特定的辅助线程,这些线程的默认名称具有极高的辨识度。如果 Frida 注入成功,进程中通常会出现以下命名的线程:核心思路是拦截对 /proc​ 目录下 comm​ 或 status​ 文件的读取操作。当发现 App 试图读取特定线程的信息时,检查读取到的内容,如果是 gmain​ 等敏感名称,将其替换为

...(已截断)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289358.htm
#2 2026-06-01 21:09:11
过来瞧瞧
#3 2026-06-01 21:09:11
过来瞧瞧
#4 2026-06-01 21:09:11
收藏学习
#5 2026-06-01 21:09:11
感谢分享
#6 2026-06-01 21:09:11
tql
#7 2026-06-01 21:09:11
感谢分享
#8 2026-06-01 21:09:11
感谢分享
#9 2026-06-01 21:09:11
感谢分享
#10 2026-06-01 21:09:11
看看
#11 2026-06-01 21:09:11
学习了,谢谢

请登录后参与讨论

立即登录 注册账号