如何用Frida重定向已运行应用的Socket流量?其实现原理是什么?
一、具体实现步骤
要修改Socket的目标地址,核心思路是Hook进程中负责建立Socket连接的函数,在函数执行时篡改传入的目标IP和端口参数。不同平台的目标函数略有差异,以下是常见场景的实现:
1. Linux/Android平台(Hook libc的connect函数)
大多数原生应用会调用libc的connect函数发起Socket连接,我们可以直接拦截这个函数并修改参数:
// frida脚本:替换Socket连接目标 Interceptor.attach(Module.findExportByName("libc.so", "connect"), { onEnter: function(args) { // args[0] = socket文件描述符,args[1] = sockaddr结构体指针,args[2] = 结构体长度 const sockaddrPtr = args[1]; const family = sockaddrPtr.readUShort(); // 地址族,AF_INET=2,AF_INET6=10 // 处理IPv4连接 if (family === 2) { // 读取原始目标信息 const originalPortNet = sockaddrPtr.add(2).readUShort(); const originalPort = (originalPortNet >> 8) | (originalPortNet << 8); // 网络字节序转主机序 const originalIpInt = sockaddrPtr.add(4).readUInt32(); const originalIp = [ (originalIpInt >> 0) & 0xff, (originalIpInt >> 8) & 0xff, (originalIpInt >> 16) & 0xff, (originalIpInt >> 24) & 0xff ].join('.'); console.log(`Original connection: ${originalIp}:${originalPort}`); // 替换为你的目标IP和端口 const targetIp = "192.168.1.100"; // 你的本地IP const targetPort = 8080; // 你的监听端口 // 将IP转为网络字节序的整数 const ipParts = targetIp.split('.').map(Number); const newIpInt = (ipParts[3] << 24) | (ipParts[2] << 16) | (ipParts[1] << 8) | ipParts[0]; sockaddrPtr.add(4).writeUInt32(newIpInt); // 将端口转为网络字节序(主机序转大端) const newPortNet = (targetPort << 8) | (targetPort >> 8); sockaddrPtr.add(2).writeUShort(newPortNet); console.log(`Redirected to: ${targetIp}:${targetPort}`); } // 如需处理IPv6,可添加family === 10的分支逻辑 } });
2. 运行脚本
将上述代码保存为redirect-socket.js,然后用Frida注入目标进程:
# 连接USB设备上的应用 frida -U -f com.your.target.app -l redirect-socket.js --no-pause
3. 特殊场景处理
如果应用使用了封装的网络库(比如Android的OkHttp、iOS的NSURLSession),可能需要Hook这些库的高层方法,而非底层的connect函数。例如Hook OkHttp的RealCall.connect方法,或者直接拦截DNS解析结果,从源头修改目标地址。
二、Frida实现深度介入的原理
Frida之所以能轻松篡改进程的Socket行为,核心依赖以下几个技术:
动态函数插桩(Dynamic Instrumentation):Frida通过底层调试接口(Linux/Android用
ptrace,Windows用远程线程注入,iOS用越狱环境的动态库注入)将一个JavaScript Agent注入目标进程。这个Agent可以找到任意函数的内存地址,然后修改函数入口处的指令,插入跳转逻辑——让程序执行到目标函数时,先进入我们的钩子函数,再继续执行原函数。直接操作进程内存:Frida提供了完整的内存读写API,允许我们直接访问和修改进程中的任意内存区域。比如上面的脚本中,我们直接读写
sockaddr结构体的内存,替换其中的IP和端口值,这种直接篡改内存的能力是实现需求的关键。跨平台兼容性:Frida针对不同操作系统封装了统一的API,不管是Android、iOS还是Windows,你都可以用几乎相同的逻辑编写Hook脚本,无需关心底层系统的差异。
无侵入式修改:整个过程不需要修改目标应用的代码或重新编译,完全在运行时动态修改程序行为,这也是Frida这类动态插桩工具的核心优势。
内容的提问来源于stack exchange,提问作者Makik

