Introduction to Android App Penetration Testing with Frida and Objection
Modern Android applications frequently handle sensitive data, necessitating robust security measures for both data in transit and data at rest. While network communication often relies on SSL/TLS, applications commonly implement SSL Pinning to prevent Man-in-the-Middle (MitM) attacks. Furthermore, client-side cryptography is extensively used to protect sensitive information before transmission or storage. Penetration testers and security researchers face the challenge of analyzing and bypassing these protections to identify vulnerabilities. Frida, a dynamic instrumentation toolkit, combined with Objection, a runtime mobile exploration toolkit built on Frida, provides a powerful duo for interactive runtime analysis, enabling us to dissect network traffic and cryptographic operations on Android applications.
This article dives deep into leveraging Frida and Objection to bypass SSL Pinning and perform live analysis of cryptographic operations within an Android application. We’ll explore practical techniques for intercepting network traffic and observing encryption/decryption processes in real-time, even when faced with sophisticated protections.
Setting Up Your Android App Pen-Testing Environment
Before we begin, ensure you have the necessary tools set up. You’ll need:
- A rooted Android device or an emulator (e.g., AVD, Genymotion)
- ADB (Android Debug Bridge) installed and configured on your host machine
- Python 3 installed on your host machine
- Frida tools installed on your host machine:
pip install frida-tools - Objection installed on your host machine:
pip install objection - Frida server running on your Android device/emulator. Download the appropriate Frida server binary for your device’s architecture from Frida’s GitHub releases, push it to your device, and execute it:
adb push frida-server /data/local/tmp/adb shell "chmod 755 /data/local/tmp/frida-server"adb shell "/data/local/tmp/frida-server &"
Verify Frida server is running by executing frida-ps -U on your host machine. This should list processes running on your device.
Bypassing SSL Pinning with Objection
SSL Pinning is a common security mechanism where an app validates the server’s certificate against a known, pre-defined certificate or public key. If the certificates don’t match, the connection is terminated, preventing proxies like Burp Suite from intercepting traffic. Objection makes bypassing this trivial.
The Command-Line Approach
To bypass SSL pinning for an application (e.g., com.example.app), simply attach Objection and use the android sslpinning disable command:
objection -g com.example.app explore
Once inside the objection shell:
android sslpinning disable
Objection will inject a Frida script that hooks common SSL/TLS certificate validation methods (e.g., in OkHttp, TrustManager, WebView) to effectively bypass the pinning checks. You should now be able to proxy the app’s traffic through Burp Suite or OWASP ZAP.
How it Works Under the Hood
Objection’s sslpinning disable command dynamically injects a Frida script. This script typically performs the following actions:
- Replaces the default
X509TrustManager.checkServerTrustedmethod to accept any server certificate. - Hooks various network libraries (like OkHttp’s
CertificatePinner) to prevent them from enforcing certificate checks. - Modifies WebView’s client to ignore SSL errors.
This allows your proxy’s self-signed certificate to be accepted by the application, enabling traffic interception.
Runtime Analysis of Cryptography with Objection
Intercepting network traffic gives us encrypted data, but to understand its contents, we often need to analyze the client-side cryptographic operations. Objection’s interactive shell and Frida’s dynamic instrumentation are invaluable here.
Identifying Cryptographic Primitives
First, we need to identify where cryptographic operations are occurring. Common Java cryptographic classes include javax.crypto.Cipher, java.security.MessageDigest, javax.crypto.spec.SecretKeySpec, and javax.crypto.spec.IvParameterSpec. We can use Objection’s class and method search capabilities:
android hooking search classes Cipherandroid hooking search methods * encrypt
Hooking `Cipher` Operations to Extract Keys, IVs, and Data
Let’s say we suspect AES encryption is being used. We want to extract the key, IV, plaintext, and ciphertext. The javax.crypto.Cipher class is central to this. Specifically, the init() method (where the key and IV are set) and doFinal() (where encryption/decryption occurs) are prime targets.
Step 1: Watch `Cipher.init()`
We can use Objection to watch the init method of the Cipher class to see what keys and IVs are being used. We’ll use dump-args and dump-return to see the method arguments and return value:
android hooking watch class_method javax.crypto.Cipher.init --dump-args --dump-return
When the application initializes a `Cipher` object, Objection will print the arguments passed to `init()`, which typically include the encryption mode, key, and IV (if applicable). The key and IV objects will need further inspection.
Step 2: Watch `Cipher.doFinal()`
Similarly, we can watch `doFinal()` to capture the data being encrypted or decrypted:
android hooking watch class_method javax.crypto.Cipher.doFinal --dump-args --dump-return
This will show the input (plaintext for encryption, ciphertext for decryption) and the output (ciphertext for encryption, plaintext for decryption) buffers. However, the output might be truncated or not fully deciphered if it’s a byte array.
Advanced Cryptographic Analysis with Custom Frida Scripts
While watch is useful, for deep dives, a custom Frida script provides more control. You can write JavaScript directly in Objection’s console using jscode or load a `.js` file.
Example: Extracting AES Key, IV, and Data
Let’s create a Frida script to intercept `Cipher.init` and `Cipher.doFinal` for AES and print the relevant details in a human-readable format. We’ll focus on `init(int opmode, java.security.Key key, java.security.spec.AlgorithmParameterSpec params)` and `doFinal(byte[] input)`.
jscode var Cipher = Java.use('javax.crypto.Cipher');var SecretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');var IvParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');Cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (opmode, key, params) { var opmodeStr = (opmode == 1) ? 'ENCRYPT_MODE' : ((opmode == 2) ? 'DECRYPT_MODE' : 'UNKNOWN_MODE'); console.log('[+] Cipher.init called with:'); console.log(' Operation Mode: ' + opmodeStr); console.log(' Key Algorithm: ' + key.getAlgorithm()); var keyBytes = Java.cast(key, SecretKeySpec).getEncoded(); console.log(' Key (Hex): ' + Array.from(keyBytes).map(b => ('0' + (b & 0xFF).toString(16)).slice(-2)).join('')); if (params.$className === 'javax.crypto.spec.IvParameterSpec') { var ivBytes = Java.cast(params, IvParameterSpec).getIV(); console.log(' IV (Hex): ' + Array.from(ivBytes).map(b => ('0' + (b & 0xFF).toString(16)).slice(-2)).join('')); } return this.init(opmode, key, params);};Cipher.doFinal.overload('[B').implementation = function (input) { var result = this.doFinal(input); console.log('[+] Cipher.doFinal called with:'); console.log(' Input (Hex): ' + Array.from(input).map(b => ('0' + (b & 0xFF).toString(16)).slice(-2)).join('')); console.log(' Output (Hex): ' + Array.from(result).map(b => ('0' + (b & 0xFF).toString(16)).slice(-2)).join('')); // Optionally try to decode if it's text try { var decodedOutput = Java.use('java.lang.String').$new(result); console.log(' Output (UTF-8): ' + decodedOutput); } catch (e) { // Not UTF-8 or invalid console.log(' Output (UTF-8): Could not decode'); } return result;};
To load this script, you can type it directly into the jscode command followed by the script, or save it to a file (e.g., crypto_hook.js) and then use:
script load crypto_hook.js
This script will print the key (in hex), IV (in hex), input data (plaintext or ciphertext in hex), and output data (ciphertext or plaintext in hex, with an attempt at UTF-8 decoding) whenever these `Cipher` methods are invoked. This level of detail is critical for understanding the encryption scheme, deriving cryptographic primitives, or even manually decrypting intercepted traffic.
Conclusion
Frida and Objection form an indispensable toolkit for Android application penetration testing. From effortlessly bypassing SSL Pinning to conducting granular, real-time analysis of cryptographic operations, these tools empower security researchers to delve deep into an app’s runtime behavior. By understanding how to effectively use Objection’s commands and craft custom Frida scripts, you can significantly enhance your ability to identify and exploit vulnerabilities related to network security and client-side data protection. The interactive nature of Objection, combined with Frida’s powerful instrumentation capabilities, makes it an ideal choice for complex runtime analysis scenarios in modern Android applications.
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 →