| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- /**
- * Initializes 'addresses' dictionary and NativeFunctions.
- */
- "use strict";
- rpc.exports = {
- setssllib: function (name) {
- console.log("setSSLLib => " + name);
- libname = name;
- initializeGlobals();
- return;
- }
- };
- var addresses = {};
- var SSL_get_fd = null;
- var SSL_get_session = null;
- var SSL_SESSION_get_id = null;
- var getpeername = null;
- var getsockname = null;
- var ntohs = null;
- var ntohl = null;
- var SSLstackwrite = null;
- var SSLstackread = null;
- var libname = "*libssl*";
- function uuid(len, radix) {
- var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
- var uuid = [], i;
- radix = radix || chars.length;
- if (len) {
- // Compact form
- for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
- } else {
- // rfc4122, version 4 form
- var r;
- // rfc4122 requires these characters
- uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
- uuid[14] = '4';
- // Fill in random data. At i==19 set the high bits of clock sequence as
- // per rfc4122, sec. 4.1.5
- for (i = 0; i < 36; i++) {
- if (!uuid[i]) {
- r = 0 | Math.random() * 16;
- uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
- }
- }
- }
- return uuid.join('');
- }
- function return_zero(args) {
- return 0;
- }
- function initializeGlobals() {
- var resolver = new ApiResolver("module");
- var exps = [
- [Process.platform == "darwin" ? "*libboringssl*" : "*libssl*", ["SSL_read", "SSL_write", "SSL_get_fd", "SSL_get_session", "SSL_SESSION_get_id"]], // for ios and Android
- [Process.platform == "darwin" ? "*libsystem*" : "*libc*", ["getpeername", "getsockname", "ntohs", "ntohl"]]
- ];
- // console.log(exps)
- for (var i = 0; i < exps.length; i++) {
- var lib = exps[i][0];
- var names = exps[i][1];
- for (var j = 0; j < names.length; j++) {
- var name = names[j];
- // console.log("exports:" + lib + "!" + name)
- var matches = resolver.enumerateMatchesSync("exports:" + lib + "!" + name);
- if (matches.length == 0) {
- if (name == "SSL_get_fd") {
- addresses["SSL_get_fd"] = 0;
- continue;
- }
- throw "Could not find " + lib + "!" + name;
- }
- else if (matches.length != 1) {
- // Sometimes Frida returns duplicates.
- var address = 0;
- var s = "";
- var duplicates_only = true;
- for (var k = 0; k < matches.length; k++) {
- if (s.length != 0) {
- s += ", ";
- }
- s += matches[k].name + "@" + matches[k].address;
- if (address == 0) {
- address = matches[k].address;
- }
- else if (!address.equals(matches[k].address)) {
- duplicates_only = false;
- }
- }
- if (!duplicates_only) {
- throw "More than one match found for " + lib + "!" + name + ": " + s;
- }
- }
- addresses[name] = matches[0].address;
- }
- }
- if (addresses["SSL_get_fd"] == 0) {
- SSL_get_fd = return_zero;
- } else {
- SSL_get_fd = new NativeFunction(addresses["SSL_get_fd"], "int", ["pointer"]);
- }
- SSL_get_session = new NativeFunction(addresses["SSL_get_session"], "pointer", ["pointer"]);
- SSL_SESSION_get_id = new NativeFunction(addresses["SSL_SESSION_get_id"], "pointer", ["pointer", "pointer"]);
- getpeername = new NativeFunction(addresses["getpeername"], "int", ["int", "pointer", "pointer"]);
- getsockname = new NativeFunction(addresses["getsockname"], "int", ["int", "pointer", "pointer"]);
- ntohs = new NativeFunction(addresses["ntohs"], "uint16", ["uint16"]);
- ntohl = new NativeFunction(addresses["ntohl"], "uint32", ["uint32"]);
- }
- initializeGlobals();
- function ipToNumber(ip) {
- var num = 0;
- if (ip == "") {
- return num;
- }
- var aNum = ip.split(".");
- if (aNum.length != 4) {
- return num;
- }
- num += parseInt(aNum[0]) << 0;
- num += parseInt(aNum[1]) << 8;
- num += parseInt(aNum[2]) << 16;
- num += parseInt(aNum[3]) << 24;
- num = num >>> 0;//这个很关键,不然可能会出现负数的情况
- return num;
- }
- /**
- * Returns a dictionary of a sockfd's "src_addr", "src_port", "dst_addr", and
- * "dst_port".
- * @param {int} sockfd The file descriptor of the socket to inspect.
- * @param {boolean} isRead If true, the context is an SSL_read call. If
- * false, the context is an SSL_write call.
- * @return {dict} Dictionary of sockfd's "src_addr", "src_port", "dst_addr",
- * and "dst_port".
- */
- function getPortsAndAddresses(sockfd, isRead) {
- var message = {};
- var src_dst = ["src", "dst"];
- for (var i = 0; i < src_dst.length; i++) {
- if ((src_dst[i] == "src") ^ isRead) {
- var sockAddr = Socket.localAddress(sockfd)
- }
- else {
- var sockAddr = Socket.peerAddress(sockfd)
- }
- if (sockAddr == null) {
- // 网络超时or其他原因可能导致socket被关闭
- message[src_dst[i] + "_port"] = 0
- message[src_dst[i] + "_addr"] = 0
- } else {
- message[src_dst[i] + "_port"] = (sockAddr.port & 0xFFFF)
- message[src_dst[i] + "_addr"] = ntohl(ipToNumber(sockAddr.ip.split(":").pop()))
- }
- }
- return message;
- }
- /**
- * Get the session_id of SSL object and return it as a hex string.
- * @param {!NativePointer} ssl A pointer to an SSL object.
- * @return {dict} A string representing the session_id of the SSL object's
- * SSL_SESSION. For example,
- * "59FD71B7B90202F359D89E66AE4E61247954E28431F6C6AC46625D472FF76336".
- */
- function getSslSessionId(ssl) {
- var session = SSL_get_session(ssl);
- if (session == 0) {
- return 0;
- }
- var len = Memory.alloc(4);
- var p = SSL_SESSION_get_id(session, len);
- len = Memory.readU32(len);
- var session_id = "";
- for (var i = 0; i < len; i++) {
- // Read a byte, convert it to a hex string (0xAB ==> "AB"), and append
- // it to session_id.
- session_id +=
- ("0" + Memory.readU8(p.add(i)).toString(16).toUpperCase()).substr(-2);
- }
- return session_id;
- }
- 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) {
- }
- });
- if (Java.available) {
- Java.perform(function () {
- 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;
- }
- //SSLpinning helper 帮助定位证书绑定的关键代码
- Java.use("java.io.File").$init.overload('java.io.File', 'java.lang.String').implementation = function (file, cert) {
- var result = this.$init(file, cert)
- var stack = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
- if (file.getPath().indexOf("cacert") >= 0 && stack.indexOf("X509TrustManagerExtensions.checkServerTrusted") >= 0) {
- var message = {};
- message["function"] = "SSLpinning position locator => " + file.getPath() + " " + cert;
- message["stack"] = stack;
- var data = Memory.alloc(1);
- send(message, Memory.readByteArray(data, 1))
- }
- return result;
- }
- 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;
- }
- if (parseFloat(Java.androidVersion) > 8) {
- Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream").write.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
- var result = this.write(bytearry, int1, int2);
- SSLstackwrite = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
- return result;
- }
- Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream").read.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
- var result = this.read(bytearry, int1, int2);
- SSLstackread = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
- return result;
- }
- }
- else {
- Java.use("com.android.org.conscrypt.OpenSSLSocketImpl$SSLOutputStream").write.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
- var result = this.write(bytearry, int1, int2);
- SSLstackwrite = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
- return result;
- }
- Java.use("com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream").read.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
- var result = this.read(bytearry, int1, int2);
- SSLstackread = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
- return result;
- }
- }
- }
- )
- }
|