script.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /**
  2. * Initializes 'addresses' dictionary and NativeFunctions.
  3. */
  4. "use strict";
  5. rpc.exports = {
  6. setssllib: function (name) {
  7. console.log("setSSLLib => " + name);
  8. libname = name;
  9. initializeGlobals();
  10. return;
  11. }
  12. };
  13. var addresses = {};
  14. var SSL_get_fd = null;
  15. var SSL_get_session = null;
  16. var SSL_SESSION_get_id = null;
  17. var getpeername = null;
  18. var getsockname = null;
  19. var ntohs = null;
  20. var ntohl = null;
  21. var SSLstackwrite = null;
  22. var SSLstackread = null;
  23. var libname = "*libssl*";
  24. function uuid(len, radix) {
  25. var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
  26. var uuid = [], i;
  27. radix = radix || chars.length;
  28. if (len) {
  29. // Compact form
  30. for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
  31. } else {
  32. // rfc4122, version 4 form
  33. var r;
  34. // rfc4122 requires these characters
  35. uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
  36. uuid[14] = '4';
  37. // Fill in random data. At i==19 set the high bits of clock sequence as
  38. // per rfc4122, sec. 4.1.5
  39. for (i = 0; i < 36; i++) {
  40. if (!uuid[i]) {
  41. r = 0 | Math.random() * 16;
  42. uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
  43. }
  44. }
  45. }
  46. return uuid.join('');
  47. }
  48. function return_zero(args) {
  49. return 0;
  50. }
  51. function initializeGlobals() {
  52. var resolver = new ApiResolver("module");
  53. var exps = [
  54. [Process.platform == "darwin" ? "*libboringssl*" : "*libssl*", ["SSL_read", "SSL_write", "SSL_get_fd", "SSL_get_session", "SSL_SESSION_get_id"]], // for ios and Android
  55. [Process.platform == "darwin" ? "*libsystem*" : "*libc*", ["getpeername", "getsockname", "ntohs", "ntohl"]]
  56. ];
  57. // console.log(exps)
  58. for (var i = 0; i < exps.length; i++) {
  59. var lib = exps[i][0];
  60. var names = exps[i][1];
  61. for (var j = 0; j < names.length; j++) {
  62. var name = names[j];
  63. // console.log("exports:" + lib + "!" + name)
  64. var matches = resolver.enumerateMatchesSync("exports:" + lib + "!" + name);
  65. if (matches.length == 0) {
  66. if (name == "SSL_get_fd") {
  67. addresses["SSL_get_fd"] = 0;
  68. continue;
  69. }
  70. throw "Could not find " + lib + "!" + name;
  71. }
  72. else if (matches.length != 1) {
  73. // Sometimes Frida returns duplicates.
  74. var address = 0;
  75. var s = "";
  76. var duplicates_only = true;
  77. for (var k = 0; k < matches.length; k++) {
  78. if (s.length != 0) {
  79. s += ", ";
  80. }
  81. s += matches[k].name + "@" + matches[k].address;
  82. if (address == 0) {
  83. address = matches[k].address;
  84. }
  85. else if (!address.equals(matches[k].address)) {
  86. duplicates_only = false;
  87. }
  88. }
  89. if (!duplicates_only) {
  90. throw "More than one match found for " + lib + "!" + name + ": " + s;
  91. }
  92. }
  93. addresses[name] = matches[0].address;
  94. }
  95. }
  96. if (addresses["SSL_get_fd"] == 0) {
  97. SSL_get_fd = return_zero;
  98. } else {
  99. SSL_get_fd = new NativeFunction(addresses["SSL_get_fd"], "int", ["pointer"]);
  100. }
  101. SSL_get_session = new NativeFunction(addresses["SSL_get_session"], "pointer", ["pointer"]);
  102. SSL_SESSION_get_id = new NativeFunction(addresses["SSL_SESSION_get_id"], "pointer", ["pointer", "pointer"]);
  103. getpeername = new NativeFunction(addresses["getpeername"], "int", ["int", "pointer", "pointer"]);
  104. getsockname = new NativeFunction(addresses["getsockname"], "int", ["int", "pointer", "pointer"]);
  105. ntohs = new NativeFunction(addresses["ntohs"], "uint16", ["uint16"]);
  106. ntohl = new NativeFunction(addresses["ntohl"], "uint32", ["uint32"]);
  107. }
  108. initializeGlobals();
  109. function ipToNumber(ip) {
  110. var num = 0;
  111. if (ip == "") {
  112. return num;
  113. }
  114. var aNum = ip.split(".");
  115. if (aNum.length != 4) {
  116. return num;
  117. }
  118. num += parseInt(aNum[0]) << 0;
  119. num += parseInt(aNum[1]) << 8;
  120. num += parseInt(aNum[2]) << 16;
  121. num += parseInt(aNum[3]) << 24;
  122. num = num >>> 0;//这个很关键,不然可能会出现负数的情况
  123. return num;
  124. }
  125. /**
  126. * Returns a dictionary of a sockfd's "src_addr", "src_port", "dst_addr", and
  127. * "dst_port".
  128. * @param {int} sockfd The file descriptor of the socket to inspect.
  129. * @param {boolean} isRead If true, the context is an SSL_read call. If
  130. * false, the context is an SSL_write call.
  131. * @return {dict} Dictionary of sockfd's "src_addr", "src_port", "dst_addr",
  132. * and "dst_port".
  133. */
  134. function getPortsAndAddresses(sockfd, isRead) {
  135. var message = {};
  136. var src_dst = ["src", "dst"];
  137. for (var i = 0; i < src_dst.length; i++) {
  138. if ((src_dst[i] == "src") ^ isRead) {
  139. var sockAddr = Socket.localAddress(sockfd)
  140. }
  141. else {
  142. var sockAddr = Socket.peerAddress(sockfd)
  143. }
  144. if (sockAddr == null) {
  145. // 网络超时or其他原因可能导致socket被关闭
  146. message[src_dst[i] + "_port"] = 0
  147. message[src_dst[i] + "_addr"] = 0
  148. } else {
  149. message[src_dst[i] + "_port"] = (sockAddr.port & 0xFFFF)
  150. message[src_dst[i] + "_addr"] = ntohl(ipToNumber(sockAddr.ip.split(":").pop()))
  151. }
  152. }
  153. return message;
  154. }
  155. /**
  156. * Get the session_id of SSL object and return it as a hex string.
  157. * @param {!NativePointer} ssl A pointer to an SSL object.
  158. * @return {dict} A string representing the session_id of the SSL object's
  159. * SSL_SESSION. For example,
  160. * "59FD71B7B90202F359D89E66AE4E61247954E28431F6C6AC46625D472FF76336".
  161. */
  162. function getSslSessionId(ssl) {
  163. var session = SSL_get_session(ssl);
  164. if (session == 0) {
  165. return 0;
  166. }
  167. var len = Memory.alloc(4);
  168. var p = SSL_SESSION_get_id(session, len);
  169. len = Memory.readU32(len);
  170. var session_id = "";
  171. for (var i = 0; i < len; i++) {
  172. // Read a byte, convert it to a hex string (0xAB ==> "AB"), and append
  173. // it to session_id.
  174. session_id +=
  175. ("0" + Memory.readU8(p.add(i)).toString(16).toUpperCase()).substr(-2);
  176. }
  177. return session_id;
  178. }
  179. Interceptor.attach(addresses["SSL_read"],
  180. {
  181. onEnter: function (args) {
  182. var message = getPortsAndAddresses(SSL_get_fd(args[0]), true);
  183. message["ssl_session_id"] = getSslSessionId(args[0]);
  184. message["function"] = "SSL_read";
  185. message["stack"] = SSLstackread;
  186. this.message = message;
  187. this.buf = args[1];
  188. },
  189. onLeave: function (retval) {
  190. retval |= 0; // Cast retval to 32-bit integer.
  191. if (retval <= 0) {
  192. return;
  193. }
  194. send(this.message, Memory.readByteArray(this.buf, retval));
  195. }
  196. });
  197. Interceptor.attach(addresses["SSL_write"],
  198. {
  199. onEnter: function (args) {
  200. var message = getPortsAndAddresses(SSL_get_fd(args[0]), false);
  201. message["ssl_session_id"] = getSslSessionId(args[0]);
  202. message["function"] = "SSL_write";
  203. message["stack"] = SSLstackwrite;
  204. send(message, Memory.readByteArray(args[1], parseInt(args[2])));
  205. },
  206. onLeave: function (retval) {
  207. }
  208. });
  209. if (Java.available) {
  210. Java.perform(function () {
  211. function storeP12(pri, p7, p12Path, p12Password) {
  212. var X509Certificate = Java.use("java.security.cert.X509Certificate")
  213. var p7X509 = Java.cast(p7, X509Certificate);
  214. var chain = Java.array("java.security.cert.X509Certificate", [p7X509])
  215. var ks = Java.use("java.security.KeyStore").getInstance("PKCS12", "BC");
  216. ks.load(null, null);
  217. ks.setKeyEntry("client", pri, Java.use('java.lang.String').$new(p12Password).toCharArray(), chain);
  218. try {
  219. var out = Java.use("java.io.FileOutputStream").$new(p12Path);
  220. ks.store(out, Java.use('java.lang.String').$new(p12Password).toCharArray())
  221. } catch (exp) {
  222. console.log(exp)
  223. }
  224. }
  225. //在服务器校验客户端的情形下,帮助dump客户端证书,并保存为p12的格式,证书密码为r0ysue
  226. Java.use("java.security.KeyStore$PrivateKeyEntry").getPrivateKey.implementation = function () {
  227. var result = this.getPrivateKey()
  228. var packageName = Java.use("android.app.ActivityThread").currentApplication().getApplicationContext().getPackageName();
  229. storeP12(this.getPrivateKey(), this.getCertificate(), '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12', 'r0ysue');
  230. var message = {};
  231. message["function"] = "dumpClinetCertificate=>" + '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12' + ' pwd: r0ysue';
  232. message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
  233. var data = Memory.alloc(1);
  234. send(message, Memory.readByteArray(data, 1))
  235. return result;
  236. }
  237. Java.use("java.security.KeyStore$PrivateKeyEntry").getCertificateChain.implementation = function () {
  238. var result = this.getCertificateChain()
  239. var packageName = Java.use("android.app.ActivityThread").currentApplication().getApplicationContext().getPackageName();
  240. storeP12(this.getPrivateKey(), this.getCertificate(), '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12', 'r0ysue');
  241. var message = {};
  242. message["function"] = "dumpClinetCertificate=>" + '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12' + ' pwd: r0ysue';
  243. message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
  244. var data = Memory.alloc(1);
  245. send(message, Memory.readByteArray(data, 1))
  246. return result;
  247. }
  248. //SSLpinning helper 帮助定位证书绑定的关键代码
  249. Java.use("java.io.File").$init.overload('java.io.File', 'java.lang.String').implementation = function (file, cert) {
  250. var result = this.$init(file, cert)
  251. var stack = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
  252. if (file.getPath().indexOf("cacert") >= 0 && stack.indexOf("X509TrustManagerExtensions.checkServerTrusted") >= 0) {
  253. var message = {};
  254. message["function"] = "SSLpinning position locator => " + file.getPath() + " " + cert;
  255. message["stack"] = stack;
  256. var data = Memory.alloc(1);
  257. send(message, Memory.readByteArray(data, 1))
  258. }
  259. return result;
  260. }
  261. Java.use("java.net.SocketOutputStream").socketWrite0.overload('java.io.FileDescriptor', '[B', 'int', 'int').implementation = function (fd, bytearry, offset, byteCount) {
  262. var result = this.socketWrite0(fd, bytearry, offset, byteCount);
  263. var message = {};
  264. message["function"] = "HTTP_send";
  265. message["ssl_session_id"] = "";
  266. message["src_addr"] = ntohl(ipToNumber((this.socket.value.getLocalAddress().toString().split(":")[0]).split("/").pop()));
  267. message["src_port"] = parseInt(this.socket.value.getLocalPort().toString());
  268. message["dst_addr"] = ntohl(ipToNumber((this.socket.value.getRemoteSocketAddress().toString().split(":")[0]).split("/").pop()));
  269. message["dst_port"] = parseInt(this.socket.value.getRemoteSocketAddress().toString().split(":").pop());
  270. message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
  271. var ptr = Memory.alloc(byteCount);
  272. for (var i = 0; i < byteCount; ++i)
  273. Memory.writeS8(ptr.add(i), bytearry[offset + i]);
  274. send(message, Memory.readByteArray(ptr, byteCount))
  275. return result;
  276. }
  277. Java.use("java.net.SocketInputStream").socketRead0.overload('java.io.FileDescriptor', '[B', 'int', 'int', 'int').implementation = function (fd, bytearry, offset, byteCount, timeout) {
  278. var result = this.socketRead0(fd, bytearry, offset, byteCount, timeout);
  279. var message = {};
  280. message["function"] = "HTTP_recv";
  281. message["ssl_session_id"] = "";
  282. message["src_addr"] = ntohl(ipToNumber((this.socket.value.getRemoteSocketAddress().toString().split(":")[0]).split("/").pop()));
  283. message["src_port"] = parseInt(this.socket.value.getRemoteSocketAddress().toString().split(":").pop());
  284. message["dst_addr"] = ntohl(ipToNumber((this.socket.value.getLocalAddress().toString().split(":")[0]).split("/").pop()));
  285. message["dst_port"] = parseInt(this.socket.value.getLocalPort());
  286. message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
  287. if (result > 0) {
  288. var ptr = Memory.alloc(result);
  289. for (var i = 0; i < result; ++i)
  290. Memory.writeS8(ptr.add(i), bytearry[offset + i]);
  291. send(message, Memory.readByteArray(ptr, result))
  292. }
  293. return result;
  294. }
  295. if (parseFloat(Java.androidVersion) > 8) {
  296. Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream").write.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
  297. var result = this.write(bytearry, int1, int2);
  298. SSLstackwrite = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
  299. return result;
  300. }
  301. Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream").read.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
  302. var result = this.read(bytearry, int1, int2);
  303. SSLstackread = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
  304. return result;
  305. }
  306. }
  307. else {
  308. Java.use("com.android.org.conscrypt.OpenSSLSocketImpl$SSLOutputStream").write.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
  309. var result = this.write(bytearry, int1, int2);
  310. SSLstackwrite = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
  311. return result;
  312. }
  313. Java.use("com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream").read.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
  314. var result = this.read(bytearry, int1, int2);
  315. SSLstackread = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
  316. return result;
  317. }
  318. }
  319. }
  320. )
  321. }