创建 script.js
parent
23640b607a
commit
528b0d8885
|
|
@ -0,0 +1,339 @@
|
|||
/**
|
||||
* 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 帮助定位证书绑定的关键代码a
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
)
|
||||
}
|
||||
Reference in New Issue