The core idea of Hook packet capture is to dump packets at all times in the plaintext state

HTTP

request

Use sockets to implement native requests

Create a new Android project and add it to mainActivity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                httpsock();
            }
        }).start();

    }
    private static void httpsock(a){
        try {
            final String host = "www.httpbin.org";
            final int port = 80;
            final String path = "/get";
            Socket socket = new Socket(host, port);

            StringBuilder sb = new StringBuilder();
            sb.append("GET " + path + "HTTP / 1.1 \ r \ n");
            sb.append("User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36\r\n");
            sb.append("Host: "+ host+"\r\n");
            sb.append("\r\n");

            OutputStream outputStream = socket.getOutputStream();
            outputStream.write(sb.toString().getBytes());

            InputStream inputStream = socket.getInputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = inputStream.read(buffer, 0, buffer.length)) ! = -1){
                Log.d("response==>".newString(Arrays.copyOf(buffer, len))); }}catch(IOException e) { e.printStackTrace(); }}}Copy the code

Run the

Analysis of the

This is the socket sending the HTTP request packet, writing the packet to an outputStream and sending it. OutputStream is a socket object method. Follow up on socket implementation

These are the interfaces to implement, to find where to implement, follow the setImpl method

You can see that the impL is the instance object, there are branches, look at factory first, search for factory = in the file to see what is assigned,

SocksSocketImpl(); , this is where the socket is implemented.

PlainSocketImpl = PlainSocketImpl = PlainSocketImpl = PlainSocketImpl

Search again for nothing, and then follow up with its parent, AbstractPlainSocketImpl

If (” SocketOutputStream() “); if (” SocketOutputStream() “);

Where you find the SocketOutputStream() object, search for the write() method, which takes bytes

Follow up with socketWrite() by calling the socketWrite0() method

You can see this method in the native layer.

Frida caught

SocketWrite0 () : socketWrite0() : socketWrite0

function main(){
    Java.perform(function(){
        //Http request
        Java.use("java.net.SocketOutputStream").socketWrite0.implementation = function(fd,bytes,off,len){
            hexdump(bytes,off,len)
            this.socketWrite0(fd,bytes,off,len)
        }
        
		// Prints a byte array
        function hexdump(bytearry,offset,length){
            var HexDump = Java.use("com.android.internal.util.HexDump")
            console.log(HexDump.dumpHexString(bytearry,offset,length))
        }

    })
}
setImmediate(main)
Copy the code

Run frida, run the script, and successfully catch the package

To improve, add request address, stack

function main(){
    Java.perform(function(){
        //Http request
        Java.use("java.net.SocketOutputStream").socketWrite0.implementation = function(fd,bytes,off,len){
            / / address
            printAddress(this.socket, true)
            / / request
            hexdump(bytes,off,len)
            / / stack
            showStacks()
            this.socketWrite0(fd,bytes,off,len)
        }
        
        function printAddress(socket, isSend){
            var localAddress = socket.value.getLocalAddress().toString()
            var remoteAddress = socket.value.getRemoteSocketAddress().toString()
            if(isSend){
                console.log(localAddress +"= = = = >"+ remoteAddress)
            }else{
                console.log(remoteAddress +"= = = = >"+ localAddress)
            }
        }
        function hexdump(bytearry,offset,length){
            var HexDump = Java.use("com.android.internal.util.HexDump")
            console.log(HexDump.dumpHexString(bytearry,offset,length))
        }
        function showStacks() {
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
        }

    })
}
setImmediate(main)
Copy the code

Request address, stack is printed

Now we’re done with the request part, and we have response

response

Analysis of the

The socket getInputStream is called. GetInputStream and getOuputStream are paired together. Or socketWrite0() is in a SocketOutputStream, so socketRead0() is in a SocketInputStream.

Frida caught

Try using Frida hook and add it to the previous code

//Http response
Java.use("java.net.SocketInputStream").socketRead0.implementation = function(fd,bytes,off,len,timeout){
    printAddress(this.socket, true)
    hexdump(bytes,off,len)
    showStacks()
    return this.socketRead0(fd,bytes,off,len,timeout)
}
Copy the code

It is also successful to capture the returned data

I caught all the HTTP packets, but what about HTTPS packets

HTTPS

request

Again, create an HTTPS request

try {
    final String host = "www.httpbin.org";
    final int port = 443;
    final String path = "/get";
    SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
    SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(host, port);

    StringBuilder sb = new StringBuilder();
    sb.append("GET " + path + "HTTP / 1.1 \ r \ n");
    sb.append("User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36\r\n");
    sb.append("Host: "+ host+"\r\n");
    sb.append("\r\n");
    Log.d("request body ===>", sb.toString());

    OutputStream outputStream = socket.getOutputStream();
    outputStream.write(sb.toString().getBytes());

    InputStream inputStream = socket.getInputStream();
    byte[] buffer = new byte[1024];
    int len;
    while ((len = inputStream.read(buffer, 0, buffer.length)) ! = -1){
        Log.d("response ==>".newString(Arrays.copyOf(buffer, len))); }}catch (IOException e) {
    e.printStackTrace();
}
Copy the code

After running

Analysis of the

Using debugging, you can quickly locate the object class,

When source search ConscryptFileDescriptorSocket

Address: aospxref.com/android-8.1…

Then search the source file for the internal class SSLOutputStream, which inherits OutputStream and overrides the original write method

Track ssl.write() in the write method

Nativecrypto.ssl_write () : nativecrypto.ssl_write () : nativecrypto.ssl_write () : NativeCrypto

Frida caught

With frida hook under org. Conscrypt. NativeCrypto class under the SSL_write () method

function main(){
    Java.perform(function(){
        //Https request
        Java.use("org.conscrypt.NativeCrypto").SSL_write.implementation = function(ssl,fd,shc,bytes,off,len,timeout){
            hexdump(bytes,off,len)
            showStacks()
            this.SSL_write(ssl,fd,shc,bytes,off,len,timeout)
        }
        
		// Prints a byte array
        function hexdump(bytearry,offset,length){
            var HexDump = Java.use("com.android.internal.util.HexDump")
            console.log(HexDump.dumpHexString(bytearry,offset,length))
        }
        function showStacks() {
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
        }
    })
}
setImmediate(main)
Copy the code

When run, you will see an error saying that the NativeCrypto class could not be found

Use the objection to look at, whether to exist in memory NativeCrypto, added com. The android prefix, reoccupy frida com.android.org.conscrypt.NativeCrypto try it

The bag was caught this time

response

The response in the same way

Frida caught

//Https response
Java.use("com.android.org.conscrypt.NativeCrypto").SSL_read.implementation = function(ssl,fd,shc,bytes,off,len,timeout){
    hexdump(bytes,off,len)
    showStacks()
    return this.SSL_read(ssl,fd,shc,bytes,off,len,timeout)
}
Copy the code

The complete code

function main(){
    Java.perform(function(){
        //Http request
        Java.use("java.net.SocketOutputStream").socketWrite0.implementation = function(fd,bytes,off,len){
            printAddress(this.socket, true)
            hexdump(bytes,off,len)
            showStacks()
            this.socketWrite0(fd,bytes,off,len)
        }
        //Http response
        Java.use("java.net.SocketInputStream").socketRead0.implementation = function(fd,bytes,off,len,timeout){
            printAddress(this.socket, false)
            hexdump(bytes,off,len)
            showStacks()
            return this.socketRead0(fd,bytes,off,len,timeout)
        }

        //Https request
        Java.use("com.android.org.conscrypt.NativeCrypto").SSL_write.implementation = function(sslNativePointer,fd,shc,bytes,off,len,timeout){
            printHttpsAddress(fd)
            hexdump(bytes,off,len)
            showStacks()
            return this.SSL_write(sslNativePointer,fd,shc,bytes,off,len,timeout)
        }
        //Https response
        Java.use("com.android.org.conscrypt.NativeCrypto").SSL_read.implementation = function(sslNativePointer,fd,shc,bytes,off,len,timeout){
            printHttpsAddress(fd)
            hexdump(bytes,off,len)
            showStacks()
            return this.SSL_read(sslNativePointer,fd,shc,bytes,off,len,timeout)
        }

        function printHttpsAddress(fd, isSend){
            var local = Socket.localAddress(fd.getInt$())
            var peer = Socket.peerAddress(fd.getInt$())
            if(isSend){
                console.log(local.ip+":"+local.port +"= = = = >"+ peer.ip+":"+peer.port)
            }else{
                console.log(peer.ip+":"+peer.port +"= = = = >"+ local.ip+":"+local.port)
            }
        }

        function printAddress(socket, isSend){
            var localAddress = socket.value.getLocalAddress().toString()
            var remoteAddress = socket.value.getRemoteSocketAddress().toString()
            if(isSend){
                console.log(localAddress +"= = = = >"+ remoteAddress)
            }else{
                console.log(remoteAddress +"= = = = >"+ localAddress)
            }
        }

        function hexdump(bytearry,offset,length){
            var HexDump = Java.use("com.android.internal.util.HexDump")
            console.log(HexDump.dumpHexString(bytearry,offset,length))
        }
        
        function showStacks() {
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
        }
    })
}
setImmediate(main)
Copy the code