socker协议分析

分析思路:
1、堆栈回溯
2、控制流分析与数据流分析
3、关键字符串、关键API定位

java层Socket抓包溯源

tcp
java.net.SocketInputStream
		|
		.......
		|
		java层
				|
				socketRead0 (jni)
							|
							native层
java.net.SocketOutputStream
		|
		.......
		|
		java层
				|
				socketWrite0 (jni)
							|
							native层
function LogPrint(log) {
    var theDate = new Date();
    var hour = theDate.getHours();
    var minute = theDate.getMinutes();
    var second = theDate.getSeconds();
    var mSecond = theDate.getMilliseconds();

    hour < 10 ? hour = "0" + hour : hour;
    minute < 10 ? minute = "0" + minute : minute;
    second < 10 ? second = "0" + second : second;
    mSecond < 10 ? mSecond = "00" + mSecond : mSecond < 100 ? mSecond = "0" + mSecond : mSecond;
    var time = hour + ":" + minute + ":" + second + ":" + mSecond;
    var threadid = Process.getCurrentThreadId();
    console.log("[" + time + "]" + "->threadid:" + threadid + "--" + log);

}

function printJavaStack(name) {
    Java.perform(function () {
        var Exception = Java.use("java.lang.Exception");
        var ins = Exception.$new("Exception");
        var straces = ins.getStackTrace();
        if (straces != undefined && straces != null) {
            var strace = straces.toString();
            var replaceStr = strace.replace(/,/g, " \n ");
            LogPrint("=============================" + name + " Stack strat=======================");
            LogPrint(replaceStr);
            LogPrint("=============================" + name + " Stack end======================= \n ");
            Exception.$dispose();
        }
    });
}

function isprintable(value) {
    if (value >= 32 && value <= 126) {
        return true;
    }
    return false;
}

function hooktcp() {
    Java.perform(function () {
        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);
            printJavaStack('tcp connect...')
            return this.$init(arg0, arg1);
        }
        var SocketInputStreamClass = Java.use('java.net.SocketInputStream');
        //socketRead0
        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 + ",content:" + JSON.stringify(arg1));
            var bytearray = Java.array('byte', arg1);
            var content = '';
            for (var i = 0; i < size; i++) {
                if (isprintable(bytearray[i])) {
                    content = content + String.fromCharCode(bytearray[i]);
                }
            }
            var socketimpl = this.impl.value;
            var address = socketimpl.address.value;
            var port = socketimpl.port.value;

            console.log("\naddress:" + address + ",port" + port + "\n" + JSON.stringify(this.socket.value) + "\n[" + Process.getCurrentThreadId() + "]receive:" + content);
            printJavaStack('socketRead0')
            return size;
        }
        var SocketOutPutStreamClass = Java.use('java.net.SocketOutputStream');
        SocketOutPutStreamClass.socketWrite0.implementation = function (arg0, arg1, arg2, arg3) {
            var result = this.socketWrite0(arg0, arg1, arg2, arg3);
            //console.log("[" + Process.getCurrentThreadId() + "]socketWrite0:len:" + arg3 + "--content:" + JSON.stringify(arg1));
            var bytearray = Java.array('byte', arg1);
            var content = '';
            for (var i = 0; i < arg3; i++) {

                if (isprintable(bytearray[i])) {
                    content = content + String.fromCharCode(bytearray[i]);
                }
            }
            var socketimpl = this.impl.value;
            var address = socketimpl.address.value;
            var port = socketimpl.port.value;
            console.log("send address:" + address + ",port" + port + "[" + Process.getCurrentThreadId() + "]send:" + content);
            console.log("\n" + JSON.stringify(this.socket.value) + "\n[" + Process.getCurrentThreadId() + "]send:" + content);
            printJavaStack('socketWrite0')
            return result;
        }
    })
}

function main() {
    hooktcp();
}

setImmediate(main)
udp 
java.net.DatagramSocket.send
	|
	PlainDatagramSockerImpl.send
		|
		IoBridge.sendto
				|
				java层
					|
					libcore.io.Linux.sendtoBytes (jni)
						|
						native层
						
java.net.DatagramSocket.receive
	|
	....
			|
				java层
					|
					libcore.io.Linux.recvfromBytes (jni)
						|
						native层

java.net.DatagramSocket.send

function LogPrint(log) {
    var theDate = new Date();
    var hour = theDate.getHours();
    var minute = theDate.getMinutes();
    var second = theDate.getSeconds();
    var mSecond = theDate.getMilliseconds();

    hour < 10 ? hour = "0" + hour : hour;
    minute < 10 ? minute = "0" + minute : minute;
    second < 10 ? second = "0" + second : second;
    mSecond < 10 ? mSecond = "00" + mSecond : mSecond < 100 ? mSecond = "0" + mSecond : mSecond;
    var time = hour + ":" + minute + ":" + second + ":" + mSecond;
    var threadid = Process.getCurrentThreadId();
    console.log("[" + time + "]" + "->threadid:" + threadid + "--" + log);

}

function printJavaStack(name) {
    Java.perform(function () {
        var Exception = Java.use("java.lang.Exception");
        var ins = Exception.$new("Exception");
        var straces = ins.getStackTrace();
        if (straces != undefined && straces != null) {
            var strace = straces.toString();
            var replaceStr = strace.replace(/,/g, " \n ");
            LogPrint("=============================" + name + " Stack strat=======================");
            LogPrint(replaceStr);
            LogPrint("=============================" + name + " Stack end======================= \n ");
            Exception.$dispose();
        }
    });
}

function isprintable(value) {
    if (value >= 32 && value <= 126) {
        return true;
    }
    return false;
}

function hookudp() {
    Java.perform(function () {
        var LinuxClass = Java.use('libcore.io.Linux');
        //private native int recvfromBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException;
        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++) {

                if (isprintable(bytearray[i])) {
                    content = content + String.fromCharCode(bytearray[i]);
                }

            }
            console.log("address:" + arg5 + " [" + Process.getCurrentThreadId() + "]recvfromBytes:size:" + size + ",content:" + JSON.stringify(arg1) + "---content," + content);
            printJavaStack('recvfromBytes');
            return size;
        }
        //private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException;
        // private native int sendtoBytes(FileDescriptor fd, Object buffer, int byteOffset, int byteCount, int flags, SocketAddress address) throws ErrnoException, SocketException;
        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++) {
                if (isprintable(bytearray[i])) {
                    content = content + String.fromCharCode(bytearray[i]);
                }

            }
            console.log("address:" + arg5 + ",port" + arg6 + " [" + Process.getCurrentThreadId() + "]LinuxClass11.sendtoBytes:len:" + size + "--content:" + JSON.stringify(arg1) + "--content:" + content);
            printJavaStack('LinuxClass11.sendtoBytes')
            return size;
        }
        LinuxClass.sendtoBytes.overload('java.io.FileDescriptor', 'java.lang.Object', 'int', 'int', 'int', 'java.net.SocketAddress').implementation = function (arg0, arg1, arg2, arg3, arg4, arg5) {
            var size = this.sendtoBytes(arg0, arg1, arg2, arg3, arg4, arg5);
            var bytearray = Java.array('byte', arg1);
            var content = "";
            for (var i = 0; i < size; i++) {
                if (isprintable(bytearray[i])) {
                    content = content + String.fromCharCode(bytearray[i]);
                }
            }
            console.log("address:" + arg5 + " [" + Process.getCurrentThreadId() + "]LinuxClass22.sendtoBytes:len:" + size + "--content:" + JSON.stringify(arg1) + ",content:" + content);
            printJavaStack('LinuxClass22.sendtoBytes')
            return size;
        }


    })

}

function main() {
    hookudp();
}

setImmediate(main)

java层SSL抓包溯源

aosp默认使用okhttp

sslSocker->com.android.org.conscrypt.OpenSSLSocketImplWrapper

发送数据
com.android.org.conscrypt.OpenSSLSocketImpl$SSLSocketOutStream
	|
	write
		|
		com.android.org.conscrypt.NativeCrypto.SSL_write (jni,此时证书加密前的数据)
			|
			native层
		

接收数据
com.android.org.conscrypt.OpenSSLSocketImpl$SSLSocketInputStream
	|
	read
		|
		com.android.org.conscrypt.NativeCrypto.SSL_read (jni,此时证书解密后的数据)
			|
			native层
function LogPrint(log) {
    var theDate = new Date();
    var hour = theDate.getHours();
    var minute = theDate.getMinutes();
    var second = theDate.getSeconds();
    var mSecond = theDate.getMilliseconds();

    hour < 10 ? hour = "0" + hour : hour;
    minute < 10 ? minute = "0" + minute : minute;
    second < 10 ? second = "0" + second : second;
    mSecond < 10 ? mSecond = "00" + mSecond : mSecond < 100 ? mSecond = "0" + mSecond : mSecond;
    var time = hour + ":" + minute + ":" + second + ":" + mSecond;
    var threadid = Process.getCurrentThreadId();
    console.log("[" + time + "]" + "->threadid:" + threadid + "--" + log);

}

function printJavaStack(name) {
    Java.perform(function () {
        var Exception = Java.use("java.lang.Exception");
        var ins = Exception.$new("Exception");
        var straces = ins.getStackTrace();
        if (straces != undefined && straces != null) {
            var strace = straces.toString();
            var replaceStr = strace.replace(/,/g, " \n ");
            LogPrint("=============================" + name + " Stack strat=======================");
            LogPrint(replaceStr);
            LogPrint("=============================" + name + " Stack end======================= \n ");
            Exception.$dispose();
        }
    });
}
function getsocketdetail(fd) {
    var result = "";
    var type = Socket.type(fd);
    if (type != null) {
        result = result + "type:" + type;
        var peer = Socket.peerAddress(fd);
        var local = Socket.localAddress(fd);
        result = result + ",address:" + JSON.stringify(peer) + ",local:" + JSON.stringify(local);
    } else {
        result = "unknown";
    }
    return result;

}

function printNativeStack(context, name) {
    //Debug.
    var array = Thread.backtrace(context, Backtracer.ACCURATE);
    var first = DebugSymbol.fromAddress(array[0]);
    if (first.toString().indexOf('libopenjdk.so!NET_Send') < 0) {
        var trace = Thread.backtrace(context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n");
        LogPrint("-----------start:" + name + "--------------");
        LogPrint(trace);
        LogPrint("-----------end:" + name + "--------------");
    }

}
function isprintable(value) {
    if (value >= 32 && value <= 126) {
        return true;
    }
    return false;
}
function hookssl() {
    Java.perform(function () {
        var NativeCryptoClass = Java.use('com.android.org.conscrypt.NativeCrypto');
        NativeCryptoClass.SSL_read.implementation = function (arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
            var size = this.SSL_read(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
            var bytearray = Java.array('byte', arg3);
            var content = '';
            for (var i = 0; i < size; i++) {
                if (isprintable(bytearray[i])) {
                    content = content + String.fromCharCode(bytearray[i]);
                }
            }
            console.log("\n[" + Process.getCurrentThreadId() + "]ssl receive:" + content);
            printJavaStack('NativeCryptoClass.read')
            return size;
        }
        NativeCryptoClass.SSL_write.implementation = function (arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
            var result = this.SSL_write(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
            var bytearray = Java.array('byte', arg3);
            var content = '';
            for (var i = 0; i < arg5; i++) {
                if (isprintable(bytearray[i])) {
                    content = content + String.fromCharCode(bytearray[i]);
                }
            }
            console.log("\n[" + Process.getCurrentThreadId() + "]ssl send:" + content);
            printJavaStack('NativeCryptoClass.SSL_write')
            return result;
        }
    })
}
function enumerate() {
    Java.perform(function () {
        Java.enumerateLoadedClassesSync().forEach(function (classname) {
            if (classname.indexOf("NativeCrypto") >= 0) {
                console.log(classname);
            }
        })
    })
}

function main() {
    //enumerate();
    hookssl();
}

setImmediate(main)
com.android.org.conscrypt.NativeCrypto.SSL_read 太深了,到上一层
com.android.org.conscrypt.OpenSSLSocketImpl$SSLSocketInputStream拿ip和端口的信息
function LogPrint(log) {
    var theDate = new Date();
    var hour = theDate.getHours();
    var minute = theDate.getMinutes();
    var second = theDate.getSeconds();
    var mSecond = theDate.getMilliseconds();

    hour < 10 ? hour = "0" + hour : hour;
    minute < 10 ? minute = "0" + minute : minute;
    second < 10 ? second = "0" + second : second;
    mSecond < 10 ? mSecond = "00" + mSecond : mSecond < 100 ? mSecond = "0" + mSecond : mSecond;
    var time = hour + ":" + minute + ":" + second + ":" + mSecond;
    var threadid = Process.getCurrentThreadId();
    console.log("[" + time + "]" + "->threadid:" + threadid + "--" + log);

}

function printJavaStack(name) {
    Java.perform(function () {
        var Exception = Java.use("java.lang.Exception");
        var ins = Exception.$new("Exception");
        var straces = ins.getStackTrace();
        if (straces != undefined && straces != null) {
            var strace = straces.toString();
            var replaceStr = strace.replace(/,/g, " \n ");
            LogPrint("=============================" + name + " Stack strat=======================");
            LogPrint(replaceStr);
            LogPrint("=============================" + name + " Stack end======================= \n ");
            Exception.$dispose();
        }
    });
}

function isprintable(value) {
    if (value >= 32 && value <= 126) {
        return true;
    }
    return false;
}

function hooksslsocket() {
    Java.perform(function () {
        var SSLInputStreamClass = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream');
        //public int read(byte[] buf, int offset, int byteCount)
        SSLInputStreamClass.read.overload().implementation = function () {
            var value = this.read();
            var sslsocketimplwrapper = this.this$0.value;
            console.log("SSLInputStreamClass.read 1obj->" + sslsocketimplwrapper);
            var socket = sslsocketimplwrapper.socket.value;
            console.log("SSLInputStreamClass.read 1socket->" + socket);
            //console.log("[" + Process.getCurrentThreadId() + "]SSLInputStreamClass.read:len:" + 4 + "--content:" + JSON.stringify(value));
            console.log("[" + Process.getCurrentThreadId() + "]sslsocket read a int:" + value);
            printJavaStack('sslInputStream.read()')
            return value;
        }

        SSLInputStreamClass.read.overload('[B', 'int', 'int').implementation = function (arg0, arg1, arg2) {
            var size = this.read(arg0, arg1, arg2);
            //内部类对象直接得到外部类对象的方法
            var sslsocketimplwrapper = this.this$0.value;
            console.log("SSLInputStreamClass.read 2obj->" + sslsocketimplwrapper);
            var socket = sslsocketimplwrapper.socket.value;
            console.log("SSLInputStreamClass.read 2socket->" + socket);
            //console.log("[" + Process.getCurrentThreadId() + "]SSLInputStreamClass.read:len:" + size + "--content:" + JSON.stringify(arg0));
            var bytearray = Java.array('byte', arg0);
            var content = '';
            for (var i = 0; i < size; i++) {
                if (isprintable(bytearray[i])) {
                    content = content + String.fromCharCode(bytearray[i]);
                }
            }
            /*            var socketimpl = this.impl.value;
                        var address = socketimpl.address.value;
                        var port = socketimpl.port.value;*/
            console.log("[" + Process.getCurrentThreadId() + "]sslsocket read:" + content);
            //console.log("\n" + JSON.stringify(this.socket.value) + "\n[" + Process.getCurrentThreadId() + "]send:" + content);
            printJavaStack('sslInputStream.read')
            return size;
        }

        var SSLOutputStreamClass = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl$SSLOutputStream');
        SSLOutputStreamClass.write.overload('int').implementation = function (arg0) {
            var result = this.write(arg0);
            //通过内部类对象得到外部类对象
            var sslsocketimplwrapper = this.this$0.value;
            console.log("SSLOutputStream 1obj->" + sslsocketimplwrapper);
            var socket = sslsocketimplwrapper.socket.value;
            console.log("SSLOutputStream 1socket->" + socket);
            /*SSLOutputStream 2obj->SSL socket over Socket[address=portal.meirishanglai.com/240.0.0.21,port=443,localPort=37563]
              SSLOutputStream 2socket->Socket[address=portal.meirishanglai.com/240.0.0.21,port=443,localPort=37563]
            */
            console.log("[" + Process.getCurrentThreadId() + "]write(int):len:" + 4 + "--content:" + arg0);
            printJavaStack('sslOutputStream.write(int)')
            return result;
        }

        //public void write(byte[] buf, int offset, int byteCount)
        SSLOutputStreamClass.write.overload('[B', 'int', 'int').implementation = function (arg0, arg1, arg2) {
            var result = this.write(arg0, arg1, arg2);
            var sslsocketimplwrapper = this.this$0.value;
            console.log("SSLOutputStream 2obj->" + sslsocketimplwrapper);
            var socket = sslsocketimplwrapper.socket.value;
            console.log("SSLOutputStream 2socket->" + socket);
            //console.log("[" + Process.getCurrentThreadId() + "]socketWrite0:len:" + arg2 + "--content:" + JSON.stringify(arg0));
            var bytearray = Java.array('byte', arg0);
            var content = '';
            for (var i = 0; i < arg2; i++) {
                if (isprintable(bytearray[i])) {
                    content = content + String.fromCharCode(bytearray[i]);
                }

            }
            /*            var socketimpl = this.impl.value;
                        var address = socketimpl.address.value;
                        var port = socketimpl.port.value;*/
            console.log("[" + Process.getCurrentThreadId() + "]sslsocket send:" + content);
            //console.log("\n" + JSON.stringify(this.socket.value) + "\n[" + Process.getCurrentThreadId() + "]send:" + content);
            printJavaStack('sslOutputStream.write')
            return result;
        }
    })
}

function main() {
    hooksslsocket();
}

setImmediate(main)

jni层Socker抓包溯源

tcp native层
libopenjdk.so - socketRead0
	|
	NET_Read
			|
			libc.so - recvfrom
				|
				系统调用(可以在自己的so中实现recvfrom,然后调用系统调用号)
					|
					内核

libopenjdk.so - socketWrite0
	|
	NET_Send
			|
			libc.so - sendto
				|
				系统调用
					|
					内核
function LogPrint(log) {
    var theDate = new Date();
    var hour = theDate.getHours();
    var minute = theDate.getMinutes();
    var second = theDate.getSeconds();
    var mSecond = theDate.getMilliseconds();

    hour < 10 ? hour = "0" + hour : hour;
    minute < 10 ? minute = "0" + minute : minute;
    second < 10 ? second = "0" + second : second;
    mSecond < 10 ? mSecond = "00" + mSecond : mSecond < 100 ? mSecond = "0" + mSecond : mSecond;
    var time = hour + ":" + minute + ":" + second + ":" + mSecond;
    var threadid = Process.getCurrentThreadId();
    console.log("[" + time + "]" + "->threadid:" + threadid + "--" + log);

}

function printNativeStack(context, name) {
    //Debug.
    var array = Thread.backtrace(context, Backtracer.ACCURATE);
    var first = DebugSymbol.fromAddress(array[0]);
    if (first.toString().indexOf('libopenjdk.so!NET_Send') < 0) {
        var trace = Thread.backtrace(context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n");
        LogPrint("-----------start:" + name + "--------------");
        LogPrint(trace);
        LogPrint("-----------end:" + name + "--------------");
    }

}

function printJavaStack(name) {
    Java.perform(function () {
        var Exception = Java.use("java.lang.Exception");
        var ins = Exception.$new("Exception");
        var straces = ins.getStackTrace();
        if (straces != undefined && straces != null) {
            var strace = straces.toString();
            var replaceStr = strace.replace(/,/g, " \n ");
            LogPrint("=============================" + name + " Stack strat=======================");
            LogPrint(replaceStr);
            LogPrint("=============================" + name + " Stack end======================= \n ");
            Exception.$dispose();
        }
    });
}

function isprintable(value) {
    if (value >= 32 && value <= 126) {
        return true;
    }
    return false;
}

function getsocketdetail(fd) {
    var result = "";
    var type = Socket.type(fd);
    if (type != null) {
        result = result + "type:" + type;
        var peer = Socket.peerAddress(fd);
        var local = Socket.localAddress(fd);
        result = result + ",address:" + JSON.stringify(peer) + ",local:" + JSON.stringify(local);
    } else {
        result = "unknown";
    }
    return result;

}

function hooklibc() {
    var libcmodule = Process.getModuleByName("libc.so");
    var recvfrom_addr = libcmodule.getExportByName("recvfrom");
    var sendto_addr = libcmodule.getExportByName("sendto");
    console.log(recvfrom_addr + "---" + sendto_addr);
    //ssize_t recvfrom(int fd, void *buf, size_t n, int flags, struct sockaddr *addr, socklen_t *addr_len)
    Interceptor.attach(recvfrom_addr, {
        onEnter: function (args) {
            this.arg0 = args[0];
            this.arg1 = args[1];
            this.arg2 = args[2];

            LogPrint("go into libc.so->recvfom");

            printNativeStack(this.context, "recvfom");
        }, onLeave(retval) {
            var size = retval.toInt32();
            if (size > 0) {
                var result = getsocketdetail(this.arg0.toInt32());
                console.log(result + "---libc.so->recvfrom:" + hexdump(this.arg1, {
                    length: size
                }));
            }

            LogPrint("leave libc.so->recvfom");
        }
    });
    //ssize_t sendto(int fd, const void *buf, size_t n, int flags, const struct sockaddr *addr, socklen_t addr_len)
    Interceptor.attach(sendto_addr, {
        onEnter: function (args) {
            this.arg0 = args[0];
            this.arg1 = args[1];
            this.arg2 = args[2];
            LogPrint("go into libc.so->sendto");
            printNativeStack(this.context, "sendto");
        }, onLeave(retval) {
            var size = ptr(this.arg2).toInt32();
            if (size > 0) {
                var result = getsocketdetail(this.arg0.toInt32());
                console.log(result + "---libc.so->sendto:" + hexdump(this.arg1, {
                    length: size
                }));
            }

            LogPrint("leave libc.so->sendto");
        }
    });
}

function main() {
    hooklibc();
}

setImmediate(main);
udp
libcore.io.Linux.sendtoBytes (jni)
	|
	libc.so - sendto

libcore.io.Linux.recvfromBytes (jni)
	|
	libc.so - recvfrom
function LogPrint(log) {
    var theDate = new Date();
    var hour = theDate.getHours();
    var minute = theDate.getMinutes();
    var second = theDate.getSeconds();
    var mSecond = theDate.getMilliseconds();

    hour < 10 ? hour = "0" + hour : hour;
    minute < 10 ? minute = "0" + minute : minute;
    second < 10 ? second = "0" + second : second;
    mSecond < 10 ? mSecond = "00" + mSecond : mSecond < 100 ? mSecond = "0" + mSecond : mSecond;
    var time = hour + ":" + minute + ":" + second + ":" + mSecond;
    var threadid = Process.getCurrentThreadId();
    console.log("[" + time + "]" + "->threadid:" + threadid + "--" + log);

}

function printNativeStack(context, name) {
    //Debug.
    var array = Thread.backtrace(context, Backtracer.ACCURATE);
    var first = DebugSymbol.fromAddress(array[0]);
    if (first.toString().indexOf('libopenjdk.so!NET_Send') < 0) {
        var trace = Thread.backtrace(context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n");
        LogPrint("-----------start:" + name + "--------------");
        LogPrint(trace);
        LogPrint("-----------end:" + name + "--------------");
    }

}

function printJavaStack(name) {
    Java.perform(function () {
        var Exception = Java.use("java.lang.Exception");
        var ins = Exception.$new("Exception");
        var straces = ins.getStackTrace();
        if (straces != undefined && straces != null) {
            var strace = straces.toString();
            var replaceStr = strace.replace(/,/g, " \n ");
            LogPrint("=============================" + name + " Stack strat=======================");
            LogPrint(replaceStr);
            LogPrint("=============================" + name + " Stack end======================= \n ");
            Exception.$dispose();
        }
    });
}

function isprintable(value) {
    if (value >= 32 && value <= 126) {
        return true;
    }
    return false;
}

function getsocketdetail(fd) {
    var result = "";
    var type = Socket.type(fd);
    if (type != null) {
        result = result + "type:" + type;
        var peer = Socket.peerAddress(fd);
        var local = Socket.localAddress(fd);
        result = result + ",address:" + JSON.stringify(peer) + ",local:" + JSON.stringify(local);
    } else {
        result = "unknown";
    }
    return result;

}

function getip(ip_ptr) {
    var result = ptr(ip_ptr).readU8() + "." + ptr(ip_ptr.add(1)).readU8() + "." + ptr(ip_ptr.add(2)).readU8() + "." + ptr(ip_ptr.add(3)).readU8()
    return result;
}

function getudpaddr(addrptr) {
    var port_ptr = addrptr.add(2);
    var port = ptr(port_ptr).readU8() * 256 + ptr(port_ptr.add(1)).readU8();
    var ip_ptr = addrptr.add(4);
    var ip_addr = getip(ip_ptr);
    return "peer:"+ip_addr+"--port:"+port;
}

function hooklibc() {
    var libcmodule = Process.getModuleByName("libc.so");
    var recvfrom_addr = libcmodule.getExportByName("recvfrom");
    var sendto_addr = libcmodule.getExportByName("sendto");
    console.log(recvfrom_addr + "---" + sendto_addr);
    //ssize_t recvfrom(int fd, void *buf, size_t n, int flags, struct sockaddr *addr, socklen_t *addr_len)
    Interceptor.attach(recvfrom_addr, {
        onEnter: function (args) {
            this.arg0 = args[0];
            this.arg1 = args[1];
            this.arg2 = args[2];
            this.arg3 = args[3];
            this.arg4 = args[4];
            this.arg5 = args[5];
            LogPrint("go into libc.so->recvfom");

            printNativeStack(this.context, "recvfom");
        }, onLeave(retval) {
            var size = retval.toInt32();
            if (size > 0) {
                var result = getsocketdetail(this.arg0.toInt32());
                if (result.indexOf('udp') >= 0) {
                    /*75struct sockaddr_in {
                    76	short	sin_family;
                    77	u_short	sin_port;
                    78	struct in_addr	sin_addr;
                    79	char	sin_zero[8];
                    80};*/
                    var sockaddr_in_ptr = this.arg4;
                    var sizeofsockaddr_in = this.arg5;

                    //02 00 22 b8 c0 a8 05 96 00 00 00 00 00 00 00 00
                    console.log("this is a recvfrom udp!->" + getudpaddr(sockaddr_in_ptr) + "---" + sizeofsockaddr_in);
                }
                console.log(Process.getCurrentThreadId()+result + "---libc.so->recvfrom:" + hexdump(this.arg1, {
                    length: size
                }));
            }

            LogPrint("leave libc.so->recvfom");
        }
    });
    //ssize_t sendto(int fd, const void *buf, size_t n, int flags, const struct sockaddr *addr, socklen_t addr_len)
    Interceptor.attach(sendto_addr, {
        onEnter: function (args) {
            this.arg0 = args[0];
            this.arg1 = args[1];
            this.arg2 = args[2];
            this.arg3 = args[3];
            this.arg4 = args[4];
            this.arg5 = args[5];
            LogPrint("go into libc.so->sendto");
            printNativeStack(this.context, "sendto");
        }, onLeave(retval) {
            var size = ptr(this.arg2).toInt32();
            if (size > 0) {
                var result = getsocketdetail(this.arg0.toInt32());
                if (result.indexOf('udp') >= 0) {
                    /*75struct sockaddr_in {
                    76	short	sin_family;
                    77	u_short	sin_port;
                    78	struct in_addr	sin_addr;
                    79	char	sin_zero[8];
                    80};*/
                    var sockaddr_in_ptr = this.arg4;
                    var sizeofsockaddr_in = this.arg5;

                    //02 00 22 b8 c0 a8 05 96 00 00 00 00 00 00 00 00
                    console.log("this is a sendto udp!->" + getudpaddr(sockaddr_in_ptr) + "---" + sizeofsockaddr_in);
                }
                console.log(Process.getCurrentThreadId()+"---"+result + "---libc.so->sendto:" + hexdump(this.arg1, {
                    length: size
                }));
            }

            LogPrint("leave libc.so->sendto");
        }
    });
}

function main() {
    hooklibc();
}

setImmediate(main);

jni层SSL抓包溯源

com.android.org.conscrypt.NativeCrypto.SSL_write (jni)
	|
	sslWrite
		|
		boringssl -> ssl_lib.c -> SSL_write
			|
			ssl3_write_app_data
				|
				do_ssl3_write (此时还是明文,之后被加密了)
					|
					ssl_write_pending
						|
						ssl_write_buffer_flush
							|
							dtls_write_buffer_flush/tls_write_buffer_flush
								|
								BIO_write
									|
									bio_io
										|
										libc.so - write

com.android.org.conscrypt.NativeCrypto.SSL_read   (jni)
	|
	libc.so - read

function hooklibc() {
    var libcmodule = Process.getModuleByName("libc.so");
    var read_addr = libcmodule.getExportByName("read");
    var write_addr = libcmodule.getExportByName("write");
    console.log(read_addr + "---" + write_addr);
    Interceptor.attach(read_addr, {
        onEnter: function (args) {
            this.arg0 = args[0];
            this.arg1 = args[1];
            this.arg2 = args[2];

            this.socketinfo = getsocketdetail(this.arg0.toInt32());
            LogPrint("go into libc.so->read_addr" + "---" + this.socketinfo);
            this.flag = false;
            if (this.socketinfo.indexOf("tcp") >= 0) {
                this.flag = true;
            }
            if (this.flag) {
                printNativeStack(this.context, Process.getCurrentThreadId() + "read");
            }


        }, onLeave(retval) {

            if (this.flag) {
                var size = retval.toInt32();
                if (size > 0) {
                    console.log(Process.getCurrentThreadId() + "---libc.so->read:" + hexdump(this.arg1, {
                        length: size
                    }));
                }
            }


            LogPrint("leave libc.so->read");
        }
    });
    Interceptor.attach(write_addr, {
        onEnter: function (args) {
            this.arg0 = args[0];
            this.arg1 = args[1];
            this.arg2 = args[2];

            this.socketinfo = getsocketdetail(this.arg0.toInt32());
            LogPrint("go into libc.so->write" + "---" + this.socketinfo);
            this.flag = false;
            if (this.socketinfo.indexOf("tcp") >= 0) {
                this.flag = true;
            }
            if (this.flag) {
                printNativeStack(this.context, Process.getCurrentThreadId() + "write");
            }


        }, onLeave(retval) {
            if (this.flag) {
                var size = ptr(this.arg2).toInt32();
                if (size > 0) {
                    console.log(Process.getCurrentThreadId() + "---libc.so->write:" + hexdump(this.arg1, {
                        length: size
                    }));
                }
            }

            LogPrint("leave libc.so->write");
        }
    });
}

自编译openssl库抓包溯源

hook 自编译 ssl so中的所有导出函数(有符号)

function hookallssl() {
    var libsslmodule = Process.getModuleByName("libssl.so");
    var SSL_get_rfd_ptr = libsslmodule.getExportByName('SSL_get_rfd');
    var SSL_get_rfd = new NativeFunction(SSL_get_rfd_ptr, 'int', ['pointer']);
    Process.enumerateModules().forEach(function (module) {
        module.enumerateExports().forEach(function (symbol) {
            var name = symbol.name;
            if (name == 'SSL_read') {
                LogPrint(JSON.stringify(module) + JSON.stringify(symbol));
            }
            if (name == 'SSL_write') {
                LogPrint(JSON.stringify(module) + JSON.stringify(symbol));
                Interceptor.attach(symbol.address, {
                    onEnter: function (args) {
                        this.arg0 = args[0];
                        this.arg1 = args[1];
                        this.arg2 = args[2];
                        LogPrint("go into " + Process.getCurrentThreadId() + "---" + JSON.stringify(module) + "---" + JSON.stringify(symbol));
                        printNativeStack(this.context, Process.getCurrentThreadId() + "---" + JSON.stringify(module) + "---" + JSON.stringify(symbol));
                        var size = ptr(this.arg2).toInt32();
                        if (size > 0) {
                            var sockfd = SSL_get_rfd(this.arg0);
                            var socketdetail = getsocketdetail(sockfd);
                            console.log(socketdetail + "---" + Process.getCurrentThreadId() + "---" + JSON.stringify(module) + "---" + JSON.stringify(symbol) + hexdump(this.arg1, {
                                length: size
                            }));
                        }
                    }, onLeave(retval) {
                        LogPrint("leave " + Process.getCurrentThreadId() + "---" + JSON.stringify(module) + "---" + JSON.stringify(symbol));

                    }
                });
            }


        })
    })
}

so中的符号被抹掉时:
通过hook libc.so中的write,read进行堆栈回溯

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值