r0capture 原理分析

r0capture,原理,分析 · 浏览次数 : 205

小编点评

**SSL_read and SSL_write Hooks** These hooks are implemented to extract client certificates and keystore information from the SSL stream during communication with an Android device. The certificates are exported to a temporary file and can be used for various purposes, such as client authentication and key exchange. **SSL_read Hook** * Informs the `storeP12()` function to export the client certificate from the SSL stream to a file named `p12Path` with the password `p12Password`. * The `p12Path` and `p12Password` are retrieved from the `arguments` array. **SSL_write Hook** * Informs the `storeP12()` function to export the client certificate chain from the SSL stream to a file named `p12Path` with the password `p12Password`. * The `p12Path` and `p12Password` are retrieved from the `arguments` array. **Key Storage and Retrieval** * When the `storeP12()` function is called, it stores the client certificate and keystore information in the system's keystore. * The keystore is opened using the `KeyStore` class, and a private key entry is created for the client certificate. * The private key is then set as the certificate's key. **Usage** These hooks can be implemented in an Android application to facilitate client certificate and keystore management. By capturing the SSL traffic and extracting the certificates, applications can use them for various purposes, such as: * Client authentication with the server * Mutual authentication between client and server * Key exchange and encryption/decryption **Additional Notes** * The specific paths and filenames for the temporary files are defined in the code. * The `storeP12()` function assumes the existence of a `KeyStore` object named `ks`. * The application should have the necessary permissions to access the keystore and write files to the specified paths.

正文

r0capture 是比较好用的抓包工具

仅限安卓平台,测试安卓7、8、9、10、11、12 可用 ;
无视所有证书校验或绑定,不用考虑任何证书的事情;
通杀TCP/IP四层模型中的应用层中的全部协议;
通杀协议包括:Http,WebSocket,Ftp,Xmpp,Imap,Smtp,Protobuf等等、以及它们的SSL版本;
通杀所有应用层框架,包括HttpUrlConnection、Okhttp1/3/4、Retrofit/Volley等等;
无视加固,不管是整体壳还是二代壳或VMP,不用考虑加固的事情;
App收发包函数定位功能
App客户端证书导出功能
host连接方式“-H”,用于Frida-server监听在非标准端口时的连接

http 抓包分析

    Java.use("java.net.SocketOutputStream").socketWrite0.overload('java.io.FileDescriptor', '[B', 'int', 'int').implementation = function (fd, bytearry, offset, byteCount) {
      var result = this.socketWrite0(fd, bytearry, offset, byteCount);
      var message = {};
      message["function"] = "HTTP_send";
      message["ssl_session_id"] = "";
      message["src_addr"] = ntohl(ipToNumber((this.socket.value.getLocalAddress().toString().split(":")[0]).split("/").pop()));
      message["src_port"] = parseInt(this.socket.value.getLocalPort().toString());
      message["dst_addr"] = ntohl(ipToNumber((this.socket.value.getRemoteSocketAddress().toString().split(":")[0]).split("/").pop()));
      message["dst_port"] = parseInt(this.socket.value.getRemoteSocketAddress().toString().split(":").pop());
      message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
      var ptr = Memory.alloc(byteCount);
      for (var i = 0; i < byteCount; ++i)
        Memory.writeS8(ptr.add(i), bytearry[offset + i]);
      send(message, Memory.readByteArray(ptr, byteCount))
      return result;
    }
    Java.use("java.net.SocketInputStream").socketRead0.overload('java.io.FileDescriptor', '[B', 'int', 'int', 'int').implementation = function (fd, bytearry, offset, byteCount, timeout) {
      var result = this.socketRead0(fd, bytearry, offset, byteCount, timeout);
      var message = {};
      message["function"] = "HTTP_recv";
      message["ssl_session_id"] = "";
      message["src_addr"] = ntohl(ipToNumber((this.socket.value.getRemoteSocketAddress().toString().split(":")[0]).split("/").pop()));
      message["src_port"] = parseInt(this.socket.value.getRemoteSocketAddress().toString().split(":").pop());
      message["dst_addr"] = ntohl(ipToNumber((this.socket.value.getLocalAddress().toString().split(":")[0]).split("/").pop()));
      message["dst_port"] = parseInt(this.socket.value.getLocalPort());
      message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
      if (result > 0) {
        var ptr = Memory.alloc(result);
        for (var i = 0; i < result; ++i)
          Memory.writeS8(ptr.add(i), bytearry[offset + i]);
        send(message, Memory.readByteArray(ptr, result))
      }
      return result;
    }

这里通过的是hook jdk 中提供的SocketInputStream 的socketWrite0 ,socketRead0 这两个底层的api接口,实现对数据进行dump,

那么不管是任何java层的第三方或者系统接口,最终会调取到socketWrite0 ,socketRead0来实现流量的收发, 这样就实现了不管是okhttp 还是retrofit ,流量最终都可以dump下来

HTTPS 抓包分析

Interceptor.attach(addresses["SSL_read"],
  {
    onEnter: function (args) {
      var message = getPortsAndAddresses(SSL_get_fd(args[0]), true);
      message["ssl_session_id"] = getSslSessionId(args[0]);
      message["function"] = "SSL_read";
      message["stack"] = SSLstackread;
      this.message = message;
      this.buf = args[1];
    },
    onLeave: function (retval) {
      retval |= 0; // Cast retval to 32-bit integer.
      if (retval <= 0) {
        return;
      }
      send(this.message, Memory.readByteArray(this.buf, retval));
    }
  });

Interceptor.attach(addresses["SSL_write"],
  {
    onEnter: function (args) {
      var message = getPortsAndAddresses(SSL_get_fd(args[0]), false);
      message["ssl_session_id"] = getSslSessionId(args[0]);
      message["function"] = "SSL_write";
      message["stack"] = SSLstackwrite;
      send(message, Memory.readByteArray(args[1], parseInt(args[2])));
    },
    onLeave: function (retval) {
    }
  });

通过hook http://aospxref.com/android-8.1.0_r81/xref/external/conscrypt/common/src/main/java/org/conscrypt/NativeCrypto.java
的 native 方法 SSL_read SSL_write, 使流量进入SSL层时对数据进行dump

客户端证书导出功能

    function storeP12(pri, p7, p12Path, p12Password) {
      var X509Certificate = Java.use("java.security.cert.X509Certificate")
      var p7X509 = Java.cast(p7, X509Certificate);
      var chain = Java.array("java.security.cert.X509Certificate", [p7X509])
      var ks = Java.use("java.security.KeyStore").getInstance("PKCS12", "BC");
      ks.load(null, null);
      ks.setKeyEntry("client", pri, Java.use('java.lang.String').$new(p12Password).toCharArray(), chain);
      try {
        var out = Java.use("java.io.FileOutputStream").$new(p12Path);
        ks.store(out, Java.use('java.lang.String').$new(p12Password).toCharArray())
      } catch (exp) {
        console.log(exp)
      }
    }
    //在服务器校验客户端的情形下,帮助dump客户端证书,并保存为p12的格式,证书密码为r0ysue
    Java.use("java.security.KeyStore$PrivateKeyEntry").getPrivateKey.implementation = function () {
      var result = this.getPrivateKey()
      var packageName = Java.use("android.app.ActivityThread").currentApplication().getApplicationContext().getPackageName();
      storeP12(this.getPrivateKey(), this.getCertificate(), '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12', 'r0ysue');
      var message = {};
      message["function"] = "dumpClinetCertificate=>" + '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12' + '   pwd: r0ysue';
      message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
      var data = Memory.alloc(1);
      send(message, Memory.readByteArray(data, 1))
      return result;
    }
    Java.use("java.security.KeyStore$PrivateKeyEntry").getCertificateChain.implementation = function () {
      var result = this.getCertificateChain()
      var packageName = Java.use("android.app.ActivityThread").currentApplication().getApplicationContext().getPackageName();
      storeP12(this.getPrivateKey(), this.getCertificate(), '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12', 'r0ysue');
      var message = {};
      message["function"] = "dumpClinetCertificate=>" + '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12' + '   pwd: r0ysue';
      message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
      var data = Memory.alloc(1);
      send(message, Memory.readByteArray(data, 1))
      return result;
    }

通过hook KeyStore$PrivateKeyEntry 将证书导出到/sdcard/Download/

与r0capture 原理分析相似的内容: