百趣云 百趣云的博客

Frida 反检测实战:从改名换端口到特征消除

Frida 的默认特征有多明显

Frida 是逆向神器,但它的默认部署在检测方面前几乎是裸奔:

  • 进程名frida-server 写在进程列表里
  • 端口:默认监听 27042
  • 内存特征:注入的 agent 带 frida 字样的内存页、特有的线程名(gum-js-loop 等)
  • 库特征frida-agent.so 出现在 maps 里

商业 App 的反 Frida 检测就是按这个清单逐项扫的。对抗思路:逐项消除特征

第一层:改名换端口(5 分钟搞定)

# 1. 二进制改名
adb push frida-server /data/local/tmp/.fs64   # 隐藏文件名

# 2. 换端口 + 只监听本地
adb shell "su -c '/data/local/tmp/.fs64 -l 127.0.0.1:8888 &'"

# 3. 端口转发给电脑
adb forward tcp:8888 tcp:8888

# 4. 客户端连接
frida -H 127.0.0.1:8888 -f com.target.app

这一步能过 60% 的检测(大部分 App 只查默认端口和进程名)。

第二层:进程名与线程名伪装

检测方会遍历 /proc/*/cmdline 找 frida 字样,以及扫描本进程的线程名找 gum-js-looppool-frida 等特征。

进程名:改名后 frida-server 的 cmdline 就是新名字,已过。

线程名:Frida 注入后在本进程创建的线程名是特征。用自定义编译的 frida(修改源码里的线程名字符串)是根治方案;不重新编译的折中方案是 hook 检测函数本身:

// hook 读取线程名的检测点
var open = Module.findExportByName('libc.so', 'open');
Interceptor.attach(open, {
    onEnter: function(args) {
        var path = args[0].readCString();
        // 检测代码遍历 /proc/self/task/*/comm 读线程名
        if (path.indexOf('/proc/self/task/') === 0 && path.endsWith('/comm')) {
            this.isCommCheck = true;
        }
    },
    onLeave: function(retval) {
        // 让它读到伪造的内容(配合 read hook)
    }
});

第三层:内存特征消除

检测方扫描自身内存找 frida agent 的特征字符串(frida-agentgum 等)。对抗:

// 1. 隐藏 maps 里的 frida 条目:hook open 对 /proc/self/maps 的读取
// 读到内容后过滤掉 frida 相关行再返回

// 2. 更彻底:用 frida 的 embed 模式或自定义 gadget,
//    把 agent 编译进自己的 so,内存里不出现 frida 字样

自定义 gadget 是工程上的甜点方案:把 frida-gadget 改名打包进 APK(或注入),连接走自定义通道,内存特征完全自定义。

第四层:检测点反制

最高效的对抗不是消除所有特征,而是直接干掉检测函数

// 逆向找到检测函数后,直接 replace 成无害返回
var checkFrida = Module.findBaseAddress('libsecurity.so').add(0x1234);
Interceptor.replace(checkFrida, new NativeCallback(function() {
    return 0;  // 永远返回"未检测到 frida"
}, 'int', []));

逆向检测函数的方法:jadx/IDA 搜 frida27042gum 等字符串,交叉引用定位检测代码。

精髓:对抗的优先级与验证

  1. 先反制检测函数,再考虑特征消除。改返回值是一行代码的事,消除内存特征是一天的工程——性价比差两个数量级
  2. 验证用"对比法":同一操作在"无 frida 环境"和"有 frida + 绕过"下各跑一次,对比请求参数和响应结果——一致才算真绕过(防静默标记型检测)
  3. 检测是组合拳,绕过要有耐心:端口、进程名、线程名、内存、行为时序,逐项排查逐项过。每过一项验证一次,别全改完再测(出问题没法定位是哪项没绕过)

总结

  1. Frida 默认特征:进程名、27042 端口、线程名、内存字符串
  2. 改名换端口过 60%,线程/内存特征要 hook 或自定义编译
  3. 最高效是反制检测函数本身(Interceptor.replace)
  4. 绕过验证用对比法,防静默标记

交流微信:run1255

By 百趣云 阅读量:3 On