Files
r0capture/script.js
T
2020-11-30 17:04:37 +08:00

227 lines
8.0 KiB
JavaScript

/**
* 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 libname = "*libssl*";
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";
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";
send(message, Memory.readByteArray(args[1], parseInt(args[2])));
},
onLeave: function (retval) {
}
});
if (Java.available) {
Java.perform(function () {
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());
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());
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;
}
})
}