移动端安全 安卓java层socket hook点分析
字数 3490 2025-08-22 12:23:30

Android Java层Socket Hook点分析教学文档

前言

Socket作为网络通信的基础接口,在Android应用开发中广泛使用。通过分析Socket源码并寻找Hook点,可以定位通信过程中的关键加密API和潜在漏洞点,扩展攻击面。本文将从TCP和UDP两种协议出发,详细分析Java层的Socket Hook点。

一、Socket基础实现

1.1 Socket基本实现过程

  1. 创建socket
  2. 绑定地址和端口
  3. 进行连接(TCP)或直接发送数据(UDP)
  4. 数据传输
  5. 关闭socket

1.2 TCP与UDP区别

  • TCP:面向连接,可靠传输,有流量控制和拥塞控制
  • UDP:无连接,不可靠传输,效率高

二、TCP Socket Hook点分析

2.1 TCP客户端实现

public class TcpClient {
    public static String ip = "x.x.x.x";
    public static int port = xxxx;
    public static boolean connected = false;
    public static Socket socket = null;
    public static OutputStream outputstream = null;
    public static InputStream inputStream = null;
    
    // 主要方法
    public static void start() { servicethread(); }
    public static void close() { /* 关闭连接 */ }
    public static void sendmsg(final String msg) { /* 发送消息 */ }
    public static void heartthread() { /* 心跳线程 */ }
    public static void receivethread() { /* 接收线程 */ }
    public static void servicethread() { /* 服务线程 */ }
}

2.2 TCP发送数据调用链

  1. java.net.SocketOutputStream.write(byte b[])
  2. java.net.SocketOutputStream.socketWrite(byte b[], int off, int len)
  3. java.net.SocketOutputStream.socketWrite0(FileDescriptor fd, byte[] b, int off, int len) (JNI函数)

2.3 TCP接收数据调用链

  1. java.net.SocketInputStream.read(byte b[])
  2. java.net.SocketInputStream.socketRead(byte b[], int off, int len)
  3. java.net.SocketInputStream.socketRead0(FileDescriptor fd, byte[] b, int off, int len) (JNI函数)

2.4 TCP Hook代码示例

function hooktcp() {
    Java.perform(function() {
        // Hook Socket构造函数
        var SocketClass = Java.use('java.net.Socket');
        SocketClass.$init.overload('java.lang.String', 'int').implementation = function(arg0, arg1) {
            console.log("[" + Process.getCurrentThreadId() + "]new Socket connection: " + arg0 + "port: " + arg1);
            return this.$init(arg0, arg1);
        }
        
        // Hook socketRead0()
        var SocketInputStreamClass = Java.use('java.net.SocketInputStream');
        SocketInputStreamClass.socketRead0.implementation = function(arg0, arg1, arg2, arg3, arg4) {
            var size = this.socketRead0(arg0, arg1, arg2, arg3, arg4);
            console.log("[" + Process.getCurrentThreadId() + "]socketRead0 > size: " + size);
            return size;
        }
        
        // Hook socketWrite0()
        var SocketOutputStreamClass = Java.use('java.net.SocketOutputStream');
        SocketOutputStreamClass.socketWrite0.implementation = function(arg0, arg1, arg2, arg3) {
            var size = this.socketWrite0(arg0, arg1, arg2, arg3);
            console.log("[" + Process.getCurrentThreadId() + "]socketWrite0 > size: " + arg3 + "--content: " + JSON.stringify(arg1));
            return size;
        }
    });
}

三、UDP Socket Hook点分析

3.1 UDP客户端实现

public class UdpClient {
    public static final String DEST_IP = "x.x.x.x";
    public static final int DEST_PORT = xxxx;
    public static final int DATA_LEN = 4096;
    public static byte[] inBuff = new byte[DATA_LEN];
    public static DatagramSocket socket;
    
    // 主要方法
    public static void udpsend(String content) { /* 发送UDP数据 */ }
    public static void receivethread() { /* 接收线程 */ }
    public static void start() { /* 启动UDP客户端 */ }
}

3.2 UDP发送数据调用链

  1. java.net.DatagramSocket.send(DatagramPacket p)
  2. java.net.PlainDatagramSocketImpl.send(DatagramPacket p)
  3. libcore.io.IoBridge.sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port)
  4. libcore.io.Libcore.os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port)
  5. libcore.io.BlockGuardOs.os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port)
  6. libcore.io.ForwardingOs.os.sendto.(fd, bytes, byteOffset, byteCount, flags, inetAddress, port)
  7. libcore.io.Linux.sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port)
  8. libcore.io.Linux.sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) (JNI函数)

3.3 UDP接收数据调用链

  1. java.net.DatagramSocket.receive(DatagramPacket p)
  2. java.net.PlainDatagramSocketImpl.receive(DatagramPacket p)
  3. libcore.io.IoBridge.recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress)
  4. libcore.io.Libcore.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress)
  5. libcore.io.BlockGuardOs.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress)
  6. libcore.io.ForwardingOs.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress)
  7. libcore.io.Linux.recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress)
  8. libcore.io.Linux.recvfromBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) (JNI函数)

3.4 UDP Hook代码示例

function hookudp() {
    Java.perform(function() {
        var LinuxClass = Java.use('libcore.io.Linux');
        
        // Hook 数据接收
        LinuxClass.recvfromBytes.implementation = function(arg0, arg1, arg2, arg3, arg4, arg5) {
            var size = this.recvfromBytes(arg0, arg1, arg2, arg3, arg4, arg5);
            var byteArray = Java.array('byte', arg1);
            var content = "";
            for(var i = 0; i < size; i++){
                content = content + String.fromCharCode(byteArray[i]);
            }
            console.log("address" + arg5 + "[" + Process.getCurrentThreadId() + "]socketRead0 > size: " + size + "--content: " + content);
            printJavaStack('recvfromBytes...');
            return size;
        }
        
        // Hook 数据发送
        LinuxClass.sendtoBytes.overload('java.io.FileDescriptor', 'java.lang.Object', 'int', 'int', 'int', 'java.net.InetAddress', 'int').implementation = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
            var size = this.sendtoBytes(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
            var byteArray = Java.array('byte', arg1);
            var content = "";
            for(var i = 0; i < size; i++){
                content = content + String.fromCharCode(byteArray[i]);
            }
            console.log("address" + arg5 + ":" + arg6 + "[" + Process.getCurrentThreadId() + "]sendtoBytes > len: " + size + "--content: " + content);
            printJavaStack('sendtoBytes()...');
            return size;
        }
    });
}

四、Hook点选择策略

4.1 关键Hook点选择

  1. 构造函数Hook:监控Socket创建时的目标地址和端口

    • java.net.Socket.$init
    • java.net.DatagramSocket.$init
  2. 数据传输Hook:监控实际发送和接收的数据

    • TCP: socketWrite0socketRead0
    • UDP: sendtoBytesrecvfromBytes
  3. 连接状态Hook:监控连接建立和关闭

    • Socket.connect()
    • Socket.close()

4.2 Hook点选择建议

  1. 精确监控:选择调用链最底层的Java方法,避免上层封装带来的干扰
  2. 性能考虑:Hook点越底层,对性能影响越小
  3. 数据完整性:选择能获取完整数据包的方法进行Hook

五、实际应用场景

5.1 安全分析场景

  1. 协议分析:通过Hook获取应用通信协议格式
  2. 加密分析:定位加密函数调用位置
  3. 漏洞挖掘:发现明文传输等安全问题

5.2 逆向工程场景

  1. 协议逆向:还原私有通信协议
  2. 数据拦截:获取应用通信内容
  3. 功能模拟:模拟客户端与服务端通信

六、注意事项

  1. Android版本差异:不同Android版本的Socket实现可能有差异,需要根据目标版本调整Hook点
  2. 多线程处理:Socket操作通常在多线程中进行,Hook时需注意线程上下文
  3. 性能影响:高频网络操作时,复杂的Hook逻辑可能影响应用性能
  4. 反调试检测:部分应用会检测Hook行为,需要采取对抗措施

七、扩展知识

7.1 Native层Hook

除了Java层Hook外,还可以考虑Hook底层的JNI函数:

  • socketWrite0socketRead0的Native实现
  • sendtoBytesrecvfromBytes的Native实现

7.2 SSL/TLS Hook

对于HTTPS等加密通信,可以Hook以下类:

  • javax.net.ssl.SSLSocket
  • org.conscrypt.OpenSSLSocketImpl
  • com.android.org.conscrypt.ConscryptFileDescriptorSocket

八、参考资源

  1. Java层socket抓包与源码分析(上)
  2. Java层socket抓包与源码分析(下)
  3. Android源码:AOSP中libcoreframeworks/base相关实现
Android Java层Socket Hook点分析教学文档 前言 Socket作为网络通信的基础接口,在Android应用开发中广泛使用。通过分析Socket源码并寻找Hook点,可以定位通信过程中的关键加密API和潜在漏洞点,扩展攻击面。本文将从TCP和UDP两种协议出发,详细分析Java层的Socket Hook点。 一、Socket基础实现 1.1 Socket基本实现过程 创建socket 绑定地址和端口 进行连接(TCP)或直接发送数据(UDP) 数据传输 关闭socket 1.2 TCP与UDP区别 TCP:面向连接,可靠传输,有流量控制和拥塞控制 UDP:无连接,不可靠传输,效率高 二、TCP Socket Hook点分析 2.1 TCP客户端实现 2.2 TCP发送数据调用链 java.net.SocketOutputStream.write(byte b[]) java.net.SocketOutputStream.socketWrite(byte b[], int off, int len) java.net.SocketOutputStream.socketWrite0(FileDescriptor fd, byte[] b, int off, int len) (JNI函数) 2.3 TCP接收数据调用链 java.net.SocketInputStream.read(byte b[]) java.net.SocketInputStream.socketRead(byte b[], int off, int len) java.net.SocketInputStream.socketRead0(FileDescriptor fd, byte[] b, int off, int len) (JNI函数) 2.4 TCP Hook代码示例 三、UDP Socket Hook点分析 3.1 UDP客户端实现 3.2 UDP发送数据调用链 java.net.DatagramSocket.send(DatagramPacket p) java.net.PlainDatagramSocketImpl.send(DatagramPacket p) libcore.io.IoBridge.sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) libcore.io.Libcore.os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port) libcore.io.BlockGuardOs.os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port) libcore.io.ForwardingOs.os.sendto.(fd, bytes, byteOffset, byteCount, flags, inetAddress, port) libcore.io.Linux.sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) libcore.io.Linux.sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) (JNI函数) 3.3 UDP接收数据调用链 java.net.DatagramSocket.receive(DatagramPacket p) java.net.PlainDatagramSocketImpl.receive(DatagramPacket p) libcore.io.IoBridge.recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) libcore.io.Libcore.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress) libcore.io.BlockGuardOs.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress) libcore.io.ForwardingOs.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress) libcore.io.Linux.recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) libcore.io.Linux.recvfromBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) (JNI函数) 3.4 UDP Hook代码示例 四、Hook点选择策略 4.1 关键Hook点选择 构造函数Hook :监控Socket创建时的目标地址和端口 java.net.Socket.$init java.net.DatagramSocket.$init 数据传输Hook :监控实际发送和接收的数据 TCP: socketWrite0 和 socketRead0 UDP: sendtoBytes 和 recvfromBytes 连接状态Hook :监控连接建立和关闭 Socket.connect() Socket.close() 4.2 Hook点选择建议 精确监控 :选择调用链最底层的Java方法,避免上层封装带来的干扰 性能考虑 :Hook点越底层,对性能影响越小 数据完整性 :选择能获取完整数据包的方法进行Hook 五、实际应用场景 5.1 安全分析场景 协议分析 :通过Hook获取应用通信协议格式 加密分析 :定位加密函数调用位置 漏洞挖掘 :发现明文传输等安全问题 5.2 逆向工程场景 协议逆向 :还原私有通信协议 数据拦截 :获取应用通信内容 功能模拟 :模拟客户端与服务端通信 六、注意事项 Android版本差异 :不同Android版本的Socket实现可能有差异,需要根据目标版本调整Hook点 多线程处理 :Socket操作通常在多线程中进行,Hook时需注意线程上下文 性能影响 :高频网络操作时,复杂的Hook逻辑可能影响应用性能 反调试检测 :部分应用会检测Hook行为,需要采取对抗措施 七、扩展知识 7.1 Native层Hook 除了Java层Hook外,还可以考虑Hook底层的JNI函数: socketWrite0 和 socketRead0 的Native实现 sendtoBytes 和 recvfromBytes 的Native实现 7.2 SSL/TLS Hook 对于HTTPS等加密通信,可以Hook以下类: javax.net.ssl.SSLSocket org.conscrypt.OpenSSLSocketImpl com.android.org.conscrypt.ConscryptFileDescriptorSocket 八、参考资源 Java层socket抓包与源码分析(上) Java层socket抓包与源码分析(下) Android源码:AOSP中 libcore 和 frameworks/base 相关实现