commit 9cade69ab9d58b53f29694a1de6844a87747a69a Author: 孟凡懂 Date: Thu May 12 15:06:41 2022 +0800 搜集部分脚本 diff --git a/code/GPS欺骗.js b/code/GPS欺骗.js new file mode 100644 index 0000000..04c471e --- /dev/null +++ b/code/GPS欺骗.js @@ -0,0 +1,14 @@ +const lat = 27.9864882; +const lng = 33.7279001; + +Java.perform(function () { + var Location = Java.use("android.location.Location"); + Location.getLatitude.implementation = function() { + send("Overwriting Lat to " + lat); + return lat; + } + Location.getLongitude.implementation = function() { + send("Overwriting Lng to " + lng); + return lng; + } +}) \ No newline at end of file diff --git a/code/InMemoryDexClassLoader dump.js b/code/InMemoryDexClassLoader dump.js new file mode 100644 index 0000000..13fdd0f --- /dev/null +++ b/code/InMemoryDexClassLoader dump.js @@ -0,0 +1,40 @@ +'use strict'; + +console.log("[*] In Memory Dex Dump v0.1 - @cryptax"); + +Java.perform(function() { + var memoryclassLoader = Java.use("dalvik.system.InMemoryDexClassLoader"); + memoryclassLoader.$init.overload('java.nio.ByteBuffer', 'java.lang.ClassLoader').implementation = function(dexbuffer, loader) { + console.log("[*] Hooking InMemoryDexClassLoader"); + var object = this.$init(dexbuffer, loader); + + /* dexbuffer is a Java ByteBuffer + you cannot dump to /sdcard unless the app has rights to + */ + var remaining = dexbuffer.remaining(); + const filename = '/data/data/YOUR-PACKAGE-NAME/dump.dex'; + + console.log("[*] Opening file name=" + filename + " to write " + remaining + " bytes"); + const f = new File(filename, 'wb'); + var buf = new Uint8Array(remaining); + for (var i = 0; i < remaining; i++) { + buf[i] = dexbuffer.get(); + //debug: console.log("buf["+i+"]="+buf[i]); + } + console.log("[*] Writing " + remaining + " bytes..."); + f.write(buf); + f.close(); + + // checking + remaining = dexbuffer.remaining(); + if (remaining > 0) { + console.log("[-] Error: There are " + remaining + " remaining bytes!"); + } else { + console.log("[+] Dex dumped successfully in " + filename); + } + + return object; + } + + +}); \ No newline at end of file diff --git a/code/Print Android Logs in console.js b/code/Print Android Logs in console.js new file mode 100644 index 0000000..9157483 --- /dev/null +++ b/code/Print Android Logs in console.js @@ -0,0 +1,46 @@ +Java.perform(function() { + var Log = Java.use("android.util.Log"); + Log.d.overload('java.lang.String', 'java.lang.String', 'java.lang.Throwable').implementation = function(a, b, c) { + console.log("The application reports Log.d(" + a.toString() + ", " + b.toString() + ")"); + return this.d(a, b, c); + }; + Log.v.overload('java.lang.String', 'java.lang.String', 'java.lang.Throwable').implementation = function(a, b, c) { + console.log("The application reports Log.v(" + a.toString() + ", " + b.toString() + ")"); + return this.v(a, b, c); + }; + + Log.i.overload('java.lang.String', 'java.lang.String', 'java.lang.Throwable').implementation = function(a, b, c) { + console.log("The application reports Log.i(" + a.toString() + ", " + b.toString() + ")"); + return this.i(a, b, c); + }; + Log.e.overload('java.lang.String', 'java.lang.String', 'java.lang.Throwable').implementation = function(a, b, c) { + console.log("The application reports Log.e(" + a.toString() + ", " + b.toString() + ")"); + return this.e(a, b, c); + }; + Log.w.overload('java.lang.String', 'java.lang.String', 'java.lang.Throwable').implementation = function(a, b, c) { + console.log("The application reports Log.w(" + a.toString() + ", " + b.toString() + ")"); + return this.w(a, b, c); + }; + Log.d.overload('java.lang.String', 'java.lang.String').implementation = function(a, b) { + console.log("The application reports Log.d(" + a.toString() + ", " + b.toString() + ")"); + return this.d(a, b); + }; + Log.v.overload('java.lang.String', 'java.lang.String').implementation = function(a, b) { + console.log("The application reports Log.v(" + a.toString() + ", " + b.toString() + ")"); + return this.v(a, b); + }; + + Log.i.overload('java.lang.String', 'java.lang.String').implementation = function(a, b) { + console.log("The application reports Log.i(" + a.toString() + ", " + b.toString() + ")"); + return this.i(a, b); + }; + Log.e.overload('java.lang.String', 'java.lang.String').implementation = function(a, b) { + console.log("The application reports Log.e(" + a.toString() + ", " + b.toString() + ")"); + return this.e(a, b); + }; + Log.w.overload('java.lang.String', 'java.lang.String').implementation = function(a, b) { + console.log("The application reports Log.w(" + a.toString() + ", " + b.toString() + ")"); + return this.w(a, b); + }; + +}); \ No newline at end of file diff --git a/code/SQLite数据库通用钩子.js b/code/SQLite数据库通用钩子.js new file mode 100644 index 0000000..9833a0e --- /dev/null +++ b/code/SQLite数据库通用钩子.js @@ -0,0 +1,156 @@ +/* + Author: secretdiary.ninja + License: (CC BY-SA 4.0) + * */ + +setImmediate(function() { + Java.perform(function() { + var sqliteDatabase = Java.use("android.database.sqlite.SQLiteDatabase"); + + // execSQL(String sql) + sqliteDatabase.execSQL.overload('java.lang.String').implementation = function(var0) { + console.log("[*] SQLiteDatabase.exeqSQL called with query: " + var0 + "\n"); + var execSQLRes = this.execSQL(var0); + return execSQLRes; + }; + + // execSqL(String, sql, Obj[] bindArgs) + sqliteDatabase.execSQL.overload('java.lang.String', '[Ljava.lang.Object;').implementation = function(var0, var1) { + console.log("[*] SQLiteDatabase.exeqSQL called with query: " + var0 + " and arguments: " + var1 + "\n"); + var execSQLRes = this.execSQL(var0, var1); + return execSQLRes; + }; + + // query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) + sqliteDatabase.query.overload('boolean', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', 'java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function(var0, var1, var2, var3, var4, var5, var6, var7, var8) { + var methodVal = "[*] SQLiteDatabase.query called."; + var logVal = "Table: " + var1 + ", selection value: " + var3 + ", selectionArgs: " + var4 + " distinct: " + var0; + console.log(methodVal + " " + logVal + "\n"); + var queryRes = this.query(var0, var1, var2, var3, var4, var5, var6, var7, var8); + return queryRes; + }; + + + // query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) + sqliteDatabase.query.overload('java.lang.String', '[Ljava.lang.String;', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', 'java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function(var0, var1, var2, var3, var4, var5, var6, var7) { + var methodVal = "[*] SQLiteDatabase.query called."; + var logVal = "Table: " + var0 + ", selection value: " + var2 + ", selectionArgs: " + var3; + console.log(methodVal + " " + logVal + "\n"); + var queryRes = this.query(var0, var1, var2, var3, var4, var5, var6, var7); + return queryRes; + }; + + // query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal) + sqliteDatabase.query.overload('boolean', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', 'java.lang.String', 'java.lang.String', 'java.lang.String', 'android.os.CancellationSignal').implementation = function(var0, var1, var2, var3, var4, var5, var6, var7, var8, var9) { + var methodVal = "[*] SQLiteDatabase.query called."; + var logVal = "Table: " + var1 + ", selection value: " + var3 + ", selectionArgs: " + var4; + console.log(methodVal + " " + logVal + "\n"); + var queryRes = this.query(var0, var1, var2, var3, var4, var5, var6, var7, var8, var9); + return queryRes; + }; + + // query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) + sqliteDatabase.query.overload('java.lang.String', '[Ljava.lang.String;', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function(var0, var1, var2, var3, var4, var5, var6) { + var methodVal = "[*] SQLiteDatabase.query called."; + var logVal = "Table: " + var0 + ", selection value: " + var2 + ", selectionArgs: " + var3; + console.log(methodVal + " " + logVal + "\n"); + var queryRes = this.query(var0, var1, var2, var3, var4, var5, var6); + return queryRes; + }; + + // queryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal) + sqliteDatabase.queryWithFactory.overload('android.database.sqlite.SQLiteDatabase$CursorFactory', 'boolean', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', 'java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function(var0, var1, var2, var3, var4, var5, var6, var7, var8, var9) { + var methodVal = "[*] SQLiteDatabase.queryWithFactory called."; + var logVal = "Table: " + var2 + ", selection value: " + var4 + ", selectionArgs: " + var5 + " distinct: " + var1; + console.log(methodVal + " " + logVal + "\n"); + var queryWithFactoryRes = this.queryWithFactory(var0, var1, var2, var3, var4, var5, var6, var7, var8, var9); + return queryWithFactoryRes; + }; + + // queryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) + sqliteDatabase.queryWithFactory.overload('android.database.sqlite.SQLiteDatabase$CursorFactory', 'boolean', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', 'java.lang.String', 'java.lang.String', 'java.lang.String', 'android.os.CancellationSignal').implementation = function(var0, var1, var2, var3, var4, var5, var6, var7, var8, var9, var10) { + var methodVal = "[*] SQLiteDatabase.queryWithFactory called."; + var logVal = "Table: " + var2 + ", selection value: " + var4 + ", selectionArgs: " + var5 + " distinct: " + var1; + console.log(methodVal + " " + logVal + "\n"); + var queryWithFactoryRes = this.queryWithFactory(var0, var1, var2, var3, var4, var5, var6, var7, var8, var9, var10); + return queryWithFactoryRes; + }; + + // rawQuery(String sql, String[] selectionArgs) + sqliteDatabase.rawQuery.overload('java.lang.String', '[Ljava.lang.String;').implementation = function(var0, var1) { + console.log("[*] SQLiteDatabase.rawQuery called with query: " + var0 + " and contentValues: " + var1 +"\n"); + var rawQueryRes = this.rawQuery(var0, var1); + return rawQueryRes; + }; + + // rawQuery(String sql, String[] selectionArgs, CancellationSignal cancellationSignal) + sqliteDatabase.rawQuery.overload('java.lang.String', '[Ljava.lang.String;', 'android.os.CancellationSignal').implementation = function(var0, var1, var2) { + console.log("[*] SQLiteDatabase.rawQuery called with query: " + var0 + " and contentValues: " + var1 +"\n"); + var rawQueryRes = this.rawQuery(var0, var1, var2); + return rawQueryRes; + }; + + // rawQueryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable, CancellationSignal cancellationSignal) + sqliteDatabase.rawQueryWithFactory.overload('android.database.sqlite.SQLiteDatabase$CursorFactory', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String', 'android.os.CancellationSignal').implementation = function(var0, var1, var2, var3, var4) { + console.log("[*] SQLiteDatabase.rawQueryWithFactory called with query: " + var1 + " and contentValues: " + var2 + "\n"); + var rawQueryWithFactoryRes = this.rawQueryWithFactory(var0, var1, var2, var3, var4); + return rawQueryWithFactoryRes; + }; + + // rawQueryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable) + sqliteDatabase.rawQueryWithFactory.overload('android.database.sqlite.SQLiteDatabase$CursorFactory', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String').implementation = function(var0, var1, var2, var3) { + console.log("[*] SQLiteDatabase.rawQueryWithFactory2 called with query: " + var1 + " and contentValues: " + var2 +"\n"); + var rawQueryWithFactoryRes = this.rawQueryWithFactory(var0, var1, var2, var3); + return rawQueryWithFactoryRes; + }; + + // insert(String table, String nullColumnHack, ContentValues values) + sqliteDatabase.insert.overload('java.lang.String', 'java.lang.String', 'android.content.ContentValues').implementation = function(var0, var1, var2) { + console.log("[*] SQLiteDatabase.insert called. Adding new value: " + var2 + " to database: " + var0 + "\n"); + var insertValueRes = this.insert(var0, var1, var2); + return insertValueRes; + }; + + // insertOrThrow(String table, String nullColumnHack, ContentValues values) + sqliteDatabase.insertOrThrow.overload('java.lang.String', 'java.lang.String', 'android.content.ContentValues').implementation = function(var0, var1, var2) { + console.log("[*] SQLiteDatabase.insertOrThrow called. Adding new value: " + var2 + " to database: " + var0 + "\n"); + var insertValueRes = this.insertOrThrow(var0, var1, var2); + return insertValueRes; + }; + + // insertOrThrow(String table, String nullColumnHack, ContentValues values) + sqliteDatabase.insertOrThrow.overload('java.lang.String', 'java.lang.String', 'android.content.ContentValues').implementation = function(var0, var1, var2) { + console.log("[*] SQLiteDatabase.insertOrThrow called. Adding new value: " + var2 + " to database: " + var0 + "\n"); + var insertValueRes = this.insertOrThrow(var0, var1, var2); + return insertValueRes; + }; + + // insertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, int conflictAlgorithm) + sqliteDatabase.insertWithOnConflict.overload('java.lang.String', 'java.lang.String', 'android.content.ContentValues', 'int').implementation = function(var0, var1, var2, var3) { + console.log("[*] SQLiteDatabase.insertWithOnConflict called. Adding new value: " + var2 + " to database: " + var0 + " and conflictAlgorithm: " + var3 + "\n"); + var insertValueRes = this.insertWithOnConflict(var0, var1, var2, var3); + return insertValueRes; + }; + + // update(String table, ContentValues values, String whereClause, String[] whereArgs) + sqliteDatabase.update.overload('java.lang.String', 'android.content.ContentValues', 'java.lang.String', '[Ljava.lang.String;').implementation = function(var0, var1, var2, var3) { + var methodVal = "[*] SQLiteDatabase.update called."; + var logVal = "Update table: " + var0 + " with where clause: " + var2 + " whereArgs:" + var3.toString() + " and values to update: " + var1.toString() +"\n"; + console.log(methodVal, logVal); + + var updateRes = this.update(var0, var1, var2, var3); + return updateRes; + }; + + // updateWithOnConflict(String table, ContentValues values, String whereClause, String[] whereArgs, int conflictAlgorithm) + sqliteDatabase.updateWithOnConflict.overload('java.lang.String', 'android.content.ContentValues', 'java.lang.String', '[Ljava.lang.String;', 'int').implementation = function(var0, var1, var2, var3, var4) { + var methodVal = "[*] SQLiteDatabase.updateWithOnConflict called."; + var logVal = "Update table: " + var0 + " with where clause: " + var2 + " whereArgs:" + var3 + " values to update: " + var1 + " and conflictAlgorithm: " + var4 +"\n"; + console.log(methodVal, logVal); + + var updateRes = this.updateWithOnConflict(var0, var1, var2, var3, var4); + return updateRes; + }; + + }); +}); \ No newline at end of file diff --git a/code/aesinfo.js b/code/aesinfo.js new file mode 100644 index 0000000..f114b8e --- /dev/null +++ b/code/aesinfo.js @@ -0,0 +1,172 @@ +Java.perform(function() { + + var use_single_byte = false; + var complete_bytes = new Array(); + var index = 0; + + + var secretKeySpecDef = Java.use('javax.crypto.spec.SecretKeySpec'); + + var ivParameterSpecDef = Java.use('javax.crypto.spec.IvParameterSpec'); + + var cipherDef = Java.use('javax.crypto.Cipher'); + + var cipherDoFinal_1 = cipherDef.doFinal.overload(); + var cipherDoFinal_2 = cipherDef.doFinal.overload('[B'); + var cipherDoFinal_3 = cipherDef.doFinal.overload('[B', 'int'); + var cipherDoFinal_4 = cipherDef.doFinal.overload('[B', 'int', 'int'); + var cipherDoFinal_5 = cipherDef.doFinal.overload('[B', 'int', 'int', '[B'); + var cipherDoFinal_6 = cipherDef.doFinal.overload('[B', 'int', 'int', '[B', 'int'); + + var cipherUpdate_1 = cipherDef.update.overload('[B'); + var cipherUpdate_2 = cipherDef.update.overload('[B', 'int', 'int'); + var cipherUpdate_3 = cipherDef.update.overload('[B', 'int', 'int', '[B'); + var cipherUpdate_4 = cipherDef.update.overload('[B', 'int', 'int', '[B', 'int'); + + var secretKeySpecDef_init_1 = secretKeySpecDef.$init.overload('[B', 'java.lang.String'); + + var secretKeySpecDef_init_2 = secretKeySpecDef.$init.overload('[B', 'int', 'int', 'java.lang.String'); + + var ivParameterSpecDef_init_1 = ivParameterSpecDef.$init.overload('[B'); + + var ivParameterSpecDef_init_2 = ivParameterSpecDef.$init.overload('[B', 'int', 'int'); + + secretKeySpecDef_init_1.implementation = function(arr, alg) { + var key = b2s(arr); + send("Creating " + alg + " secret key, plaintext:\\n" + hexdump(key)); + return secretKeySpecDef_init_1.call(this, arr, alg); + } + + secretKeySpecDef_init_2.implementation = function(arr, off, len, alg) { + var key = b2s(arr); + send("Creating " + alg + " secret key, plaintext:\\n" + hexdump(key)); + return secretKeySpecDef_init_2.call(this, arr, off, len, alg); + } + + /*ivParameterSpecDef_init_1.implementation = function(arr) + { + var iv = b2s(arr); + send("Creating IV:\\n" + hexdump(iv)); + return ivParameterSpecDef_init_1.call(this, arr); + } + + ivParameterSpecDef_init_2.implementation = function(arr, off, len) + { + var iv = b2s(arr); + send("Creating IV, plaintext:\\n" + hexdump(iv)); + return ivParameterSpecDef_init_2.call(this, arr, off, len); + }*/ + + cipherDoFinal_1.implementation = function() { + var ret = cipherDoFinal_1.call(this); + info(this.getIV(), this.getAlgorithm(), complete_bytes, ret); + return ret; + } + + cipherDoFinal_2.implementation = function(arr) { + addtoarray(arr); + var ret = cipherDoFinal_2.call(this, arr); + info(this.getIV(), this.getAlgorithm(), complete_bytes, ret); + return ret; + } + + cipherDoFinal_3.implementation = function(arr, a) { + addtoarray(arr); + var ret = cipherDoFinal_3.call(this, arr, a); + info(this.getIV(), this.getAlgorithm(), complete_bytes, ret); + return ret; + } + + cipherDoFinal_4.implementation = function(arr, a, b) { + addtoarray(arr); + var ret = cipherDoFinal_4.call(this, arr, a, b); + info(this.getIV(), this.getAlgorithm(), complete_bytes, ret); + return ret; + } + + cipherDoFinal_5.implementation = function(arr, a, b, c) { + addtoarray(arr); + var ret = cipherDoFinal_5.call(this, arr, a, b, c); + info(this.getIV(), this.getAlgorithm(), complete_bytes, ret); + return ret; + } + + cipherDoFinal_6.implementation = function(arr, a, b, c, d) { + addtoarray(arr); + var ret = cipherDoFinal_6.call(this, arr, a, b, c, d); + info(this.getIV(), this.getAlgorithm(), complete_bytes, c); + return ret; + } + + cipherUpdate_1.implementation = function(arr) { + addtoarray(arr); + return cipherUpdate_1.call(this, arr); + } + + cipherUpdate_2.implementation = function(arr, a, b) { + addtoarray(arr); + return cipherUpdate_2.call(this, arr, a, b); + } + + cipherUpdate_3.implementation = function(arr, a, b, c) { + addtoarray(arr); + return cipherUpdate_3.call(this, arr, a, b, c); + } + + cipherUpdate_4.implementation = function(arr, a, b, c, d) { + addtoarray(arr); + return cipherUpdate_4.call(this, arr, a, b, c, d); + } + + function info(iv, alg, plain, encoded) { + send("Performing encryption/decryption"); + if (iv) { + send("Initialization Vector: \\n" + hexdump(b2s(iv))); + } else { + send("Initialization Vector: " + iv); + } + send("Algorithm: " + alg); + send("In: \\n" + hexdump(b2s(plain))); + send("Out: \\n" + hexdump(b2s(encoded))); + complete_bytes = []; + index = 0; + } + + function hexdump(buffer, blockSize) { + blockSize = blockSize || 16; + var lines = []; + var hex = "0123456789ABCDEF"; + for (var b = 0; b < buffer.length; b += blockSize) { + var block = buffer.slice(b, Math.min(b + blockSize, buffer.length)); + var addr = ("0000" + b.toString(16)).slice(-4); + var codes = block.split('').map(function(ch) { + var code = ch.charCodeAt(0); + return " " + hex[(0xF0 & code) >> 4] + hex[0x0F & code]; + }).join(""); + codes += " ".repeat(blockSize - block.length); + var chars = block.replace(/[\\x00-\\x1F\\x20]/g, '.'); + chars += " ".repeat(blockSize - block.length); + lines.push(addr + " " + codes + " " + chars); + } + return lines.join("\\n"); + } + + function b2s(array) { + var result = ""; + for (var i = 0; i < array.length; i++) { + result += String.fromCharCode(modulus(array[i], 256)); + } + return result; + } + + function modulus(x, n) { + return ((x % n) + n) % n; + } + + function addtoarray(arr) { + for (var i = 0; i < arr.length; i++) { + complete_bytes[index] = arr[i]; + index = index + 1; + } + } +}); \ No newline at end of file diff --git a/code/cordova---enable-webview-debugging.js b/code/cordova---enable-webview-debugging.js new file mode 100644 index 0000000..ee80e8a --- /dev/null +++ b/code/cordova---enable-webview-debugging.js @@ -0,0 +1,13 @@ +// Usage : frida -U -f bundle_id -l enable_debug.js --no-pause +// Blog link to be added +// Written by @67616d654661636 and @sunnyrockzzs + +Java.perform(function() { + var Webview = Java.use("android.webkit.WebView") + Webview.loadUrl.overload("java.lang.String").implementation = function(url) { + console.log("\n[+]Loading URL from", url); + console.log("[+]Setting the value of setWebContentsDebuggingEnabled() to TRUE"); + this.setWebContentsDebuggingEnabled(true); + this.loadUrl.overload("java.lang.String").call(this, url); + } +}); \ No newline at end of file diff --git a/code/frida-multiple-unpinning.js b/code/frida-multiple-unpinning.js new file mode 100644 index 0000000..7bb1f40 --- /dev/null +++ b/code/frida-multiple-unpinning.js @@ -0,0 +1,730 @@ +/* Android ssl certificate pinning bypass script for various methods + by Maurizio Siddu + + Run with: + frida -U -f [APP_ID] -l frida_multiple_unpinning.js --no-pause +*/ + +setTimeout(function() { + Java.perform(function() { + console.log(''); + console.log('======'); + console.log('[#] Android Bypass for various Certificate Pinning methods [#]'); + console.log('======'); + + + var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager'); + var SSLContext = Java.use('javax.net.ssl.SSLContext'); + + // TrustManager (Android < 7) // + //////////////////////////////// + var TrustManager = Java.registerClass({ + // Implement a custom TrustManager + name: 'dev.asd.test.TrustManager', + implements: [X509TrustManager], + methods: { + checkClientTrusted: function(chain, authType) {}, + checkServerTrusted: function(chain, authType) {}, + getAcceptedIssuers: function() {return []; } + } + }); + // Prepare the TrustManager array to pass to SSLContext.init() + var TrustManagers = [TrustManager.$new()]; + // Get a handle on the init() on the SSLContext class + var SSLContext_init = SSLContext.init.overload( + '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom'); + try { + // Override the init method, specifying the custom TrustManager + SSLContext_init.implementation = function(keyManager, trustManager, secureRandom) { + console.log('[+] Bypassing Trustmanager (Android < 7) pinner'); + SSLContext_init.call(this, keyManager, TrustManagers, secureRandom); + }; + } catch (err) { + console.log('[-] TrustManager (Android < 7) pinner not found'); + //console.log(err); + } + + + + + // OkHTTPv3 (quadruple bypass) // + ///////////////////////////////// + try { + // Bypass OkHTTPv3 {1} + var okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner'); + okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function(a, b) { + console.log('[+] Bypassing OkHTTPv3 {1}: ' + a); + return; + }; + } catch (err) { + console.log('[-] OkHTTPv3 {1} pinner not found'); + //console.log(err); + } + try { + // Bypass OkHTTPv3 {2} + // This method of CertificatePinner.check is deprecated but could be found in some old Android apps + var okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner'); + okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function(a, b) { + console.log('[+] Bypassing OkHTTPv3 {2}: ' + a); + return; + }; + } catch (err) { + console.log('[-] OkHTTPv3 {2} pinner not found'); + //console.log(err); + } + try { + // Bypass OkHTTPv3 {3} + var okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner'); + okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function(a, b) { + console.log('[+] Bypassing OkHTTPv3 {3}: ' + a); + return; + }; + } catch(err) { + console.log('[-] OkHTTPv3 {3} pinner not found'); + //console.log(err); + } + try { + // Bypass OkHTTPv3 {4} + var okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner'); + //okhttp3_Activity_4['check$okhttp'].implementation = function(a, b) { + okhttp3_Activity_4.check$okhttp.overload('java.lang.String', 'kotlin.jvm.functions.Function0').implementation = function(a, b) { + console.log('[+] Bypassing OkHTTPv3 {4}: ' + a); + return; + }; + } catch(err) { + console.log('[-] OkHTTPv3 {4} pinner not found'); + //console.log(err); + } + + + + + // Trustkit (triple bypass) // + ////////////////////////////// + try { + // Bypass Trustkit {1} + var trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier'); + trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) { + console.log('[+] Bypassing Trustkit {1}: ' + a); + return true; + }; + } catch (err) { + console.log('[-] Trustkit {1} pinner not found'); + //console.log(err); + } + try { + // Bypass Trustkit {2} + var trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier'); + trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) { + console.log('[+] Bypassing Trustkit {2}: ' + a); + return true; + }; + } catch (err) { + console.log('[-] Trustkit {2} pinner not found'); + //console.log(err); + } + try { + // Bypass Trustkit {3} + var trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager'); + trustkit_PinningTrustManager.checkServerTrusted.overload('[Ljava.security.cert.X509Certificate;', 'java.lang.String').implementation = function(chain, authType) { + console.log('[+] Bypassing Trustkit {3}'); + //return; + }; + } catch (err) { + console.log('[-] Trustkit {3} pinner not found'); + //console.log(err); + } + + + + + // TrustManagerImpl (Android > 7) // + //////////////////////////////////// + try { + // Bypass TrustManagerImpl (Android > 7) {1} + var array_list = Java.use("java.util.ArrayList"); + var TrustManagerImpl_Activity_1 = Java.use('com.android.org.conscrypt.TrustManagerImpl'); + TrustManagerImpl_Activity_1.checkTrustedRecursive.implementation = function(certs, ocspData, tlsSctData, host, clientAuth, untrustedChain, trustAnchorChain, used) { + console.log('[+] Bypassing TrustManagerImpl (Android > 7) checkTrustedRecursive check: '+ host); + return array_list.$new(); + }; + } catch (err) { + console.log('[-] TrustManagerImpl (Android > 7) checkTrustedRecursive check not found'); + //console.log(err); + } + try { + // Bypass TrustManagerImpl (Android > 7) {2} (probably no more necessary) + var TrustManagerImpl_Activity_2 = Java.use('com.android.org.conscrypt.TrustManagerImpl'); + TrustManagerImpl_Activity_2.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) { + console.log('[+] Bypassing TrustManagerImpl (Android > 7) verifyChain check: ' + host); + return untrustedChain; + }; + } catch (err) { + console.log('[-] TrustManagerImpl (Android > 7) verifyChain check not found'); + //console.log(err); + } + + + + + + // Appcelerator Titanium PinningTrustManager // + /////////////////////////////////////////////// + try { + var appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager'); + appcelerator_PinningTrustManager.checkServerTrusted.implementation = function(chain, authType) { + console.log('[+] Bypassing Appcelerator PinningTrustManager'); + return; + }; + } catch (err) { + console.log('[-] Appcelerator PinningTrustManager pinner not found'); + //console.log(err); + } + + + + + // Fabric PinningTrustManager // + //////////////////////////////// + try { + var fabric_PinningTrustManager = Java.use('io.fabric.sdk.android.services.network.PinningTrustManager'); + fabric_PinningTrustManager.checkServerTrusted.implementation = function(chain, authType) { + console.log('[+] Bypassing Fabric PinningTrustManager'); + return; + }; + } catch (err) { + console.log('[-] Fabric PinningTrustManager pinner not found'); + //console.log(err); + } + + + + + // OpenSSLSocketImpl Conscrypt (double bypass) // + ///////////////////////////////////////////////// + try { + var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl'); + OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certRefs, JavaObject, authMethod) { + console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt {1}'); + }; + } catch (err) { + console.log('[-] OpenSSLSocketImpl Conscrypt {1} pinner not found'); + //console.log(err); + } + try { + var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl'); + OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certChain, authMethod) { + console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt {2}'); + }; + } catch (err) { + console.log('[-] OpenSSLSocketImpl Conscrypt {2} pinner not found'); + //console.log(err); + } + + + + + // OpenSSLEngineSocketImpl Conscrypt // + /////////////////////////////////////// + try { + var OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl'); + OpenSSLEngineSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function(a, b) { + console.log('[+] Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b); + }; + } catch (err) { + console.log('[-] OpenSSLEngineSocketImpl Conscrypt pinner not found'); + //console.log(err); + } + + + + + // OpenSSLSocketImpl Apache Harmony // + ////////////////////////////////////// + try { + var OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl'); + OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function(asn1DerEncodedCertificateChain, authMethod) { + console.log('[+] Bypassing OpenSSLSocketImpl Apache Harmony'); + }; + } catch (err) { + console.log('[-] OpenSSLSocketImpl Apache Harmony pinner not found'); + //console.log(err); + } + + + + + // PhoneGap sslCertificateChecker // + //////////////////////////////////// + try { + var phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker'); + phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function(a, b, c) { + console.log('[+] Bypassing PhoneGap sslCertificateChecker: ' + a); + return true; + }; + } catch (err) { + console.log('[-] PhoneGap sslCertificateChecker pinner not found'); + //console.log(err); + } + + + + + // IBM MobileFirst pinTrustedCertificatePublicKey (double bypass) // + //////////////////////////////////////////////////////////////////// + try { + // Bypass IBM MobileFirst {1} + var WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient'); + WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function(cert) { + console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {1}: ' + cert); + return; + }; + } catch (err) { + console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {1} pinner not found'); + //console.log(err); + } + try { + // Bypass IBM MobileFirst {2} + var WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient'); + WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function(cert) { + console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {2}: ' + cert); + return; + }; + } catch (err) { + console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {2} pinner not found'); + //console.log(err); + } + + + + + // IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass) // + /////////////////////////////////////////////////////////////////////////////////////////////////////// + try { + // Bypass IBM WorkLight {1} + var worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); + worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function(a, b) { + console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {1}: ' + a); + return; + }; + } catch (err) { + console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {1} pinner not found'); + //console.log(err); + } + try { + // Bypass IBM WorkLight {2} + var worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); + worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) { + console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {2}: ' + a); + return; + }; + } catch (err) { + console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {2} pinner not found'); + //console.log(err); + } + try { + // Bypass IBM WorkLight {3} + var worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); + worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function(a, b) { + console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {3}: ' + a); + return; + }; + } catch (err) { + console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {3} pinner not found'); + //console.log(err); + } + try { + // Bypass IBM WorkLight {4} + var worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); + worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) { + console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {4}: ' + a); + return true; + }; + } catch (err) { + console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {4} pinner not found'); + //console.log(err); + } + + + + + // Conscrypt CertPinManager // + ////////////////////////////// + try { + var conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager'); + conscrypt_CertPinManager_Activity.checkChainPinning.overload('java.lang.String', 'java.util.List').implementation = function(a, b) { + console.log('[+] Bypassing Conscrypt CertPinManager: ' + a); + //return; + return true; + }; + } catch (err) { + console.log('[-] Conscrypt CertPinManager pinner not found'); + //console.log(err); + } + + + + + // Conscrypt CertPinManager (Legacy) // + /////////////////////////////////////// + try { + var legacy_conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager'); + legacy_conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function(a, b) { + console.log('[+] Bypassing Conscrypt CertPinManager (Legacy): ' + a); + return true; + }; + } catch (err) { + console.log('[-] Conscrypt CertPinManager (Legacy) pinner not found'); + //console.log(err); + } + + + + + // CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager // + /////////////////////////////////////////////////////////////////////////////////// + try { + var cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager'); + cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function(a, b) { + console.log('[+] Bypassing CWAC-Netsecurity CertPinManager: ' + a); + return true; + }; + } catch (err) { + console.log('[-] CWAC-Netsecurity CertPinManager pinner not found'); + //console.log(err); + } + + + + + // Worklight Androidgap WLCertificatePinningPlugin // + ///////////////////////////////////////////////////// + try { + var androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin'); + androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function(a, b, c) { + console.log('[+] Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a); + return true; + }; + } catch (err) { + console.log('[-] Worklight Androidgap WLCertificatePinningPlugin pinner not found'); + //console.log(err); + } + + + + + // Netty FingerprintTrustManagerFactory // + ////////////////////////////////////////// + try { + var netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory'); + //NOTE: sometimes this below implementation could be useful + //var netty_FingerprintTrustManagerFactory = Java.use('org.jboss.netty.handler.ssl.util.FingerprintTrustManagerFactory'); + netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function(type, chain) { + console.log('[+] Bypassing Netty FingerprintTrustManagerFactory'); + }; + } catch (err) { + console.log('[-] Netty FingerprintTrustManagerFactory pinner not found'); + //console.log(err); + } + + + + + // Squareup CertificatePinner [OkHTTP + stack.getClassName() === "javax.net.ssl.SSLPeerUnverifiedException" + ); + // Retrieve the method raising the SSLPeerUnverifiedException + var callingFunctionStack = stackTrace[exceptionStackIndex + 1]; + var className = callingFunctionStack.getClassName(); + var methodName = callingFunctionStack.getMethodName(); + var callingClass = Java.use(className); + var callingMethod = callingClass[methodName]; + console.log('\x1b[36m[!] Attempting to bypass uncommon SSL Pinning method on: '+className+'.'+methodName+'\x1b[0m'); + // Skip it when already patched by Frida + if (callingMethod.implementation) { + return; + } + // Trying to patch the uncommon SSL Pinning method via implementation + var returnTypeName = callingMethod.returnType.type; + callingMethod.implementation = function() { + rudimentaryFix(returnTypeName); + }; + } catch (e) { + // Dynamic patching via implementation does not works, then trying via function overloading + //console.log('[!] The uncommon SSL Pinning method has more than one overload); + if (String(e).includes(".overload")) { + var splittedList = String(e).split(".overload"); + for (let i=2; i