移动端安全 安卓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基本实现过程
- 创建socket
- 绑定地址和端口
- 进行连接(TCP)或直接发送数据(UDP)
- 数据传输
- 关闭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发送数据调用链
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代码示例
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发送数据调用链
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代码示例
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点选择
-
构造函数Hook:监控Socket创建时的目标地址和端口
java.net.Socket.$initjava.net.DatagramSocket.$init
-
数据传输Hook:监控实际发送和接收的数据
- TCP:
socketWrite0和socketRead0 - UDP:
sendtoBytes和recvfromBytes
- TCP:
-
连接状态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.SSLSocketorg.conscrypt.OpenSSLSocketImplcom.android.org.conscrypt.ConscryptFileDescriptorSocket
八、参考资源
- Java层socket抓包与源码分析(上)
- Java层socket抓包与源码分析(下)
- Android源码:AOSP中
libcore和frameworks/base相关实现