Introduction
Android applications frequently handle sensitive data, often protected using cryptographic operations. For security analysts and penetration testers, understanding how an app implements cryptography – from key generation and usage to data encryption and hashing – is paramount. However, static analysis often falls short due to obfuscation, dynamic key generation, or native library calls.
This is where Frida, a dynamic instrumentation toolkit, becomes indispensable. Frida allows you to inject scripts into running processes, enabling you to inspect, modify, and trace functions in real-time. This cheatsheet focuses on using Frida to hook common Java cryptographic APIs in Android applications, helping you uncover keys, initialization vectors (IVs), plaintext, ciphertext, and hashed data during runtime.
Prerequisites
Before diving into the hooks, ensure you have the following setup:
- Rooted Android Device or Emulator: Frida requires root privileges to inject into system or third-party applications.
- Frida Server: Download the appropriate Frida server for your device’s architecture (e.g.,
frida-server-*-android-arm64) and run it on the Android device. - Frida-tools: Install
frida-toolson your host machine via pip (pip install frida-tools). - Basic Understanding: Familiarity with Java/Kotlin, Android application structure, and core cryptographic concepts will be beneficial.
Frida Fundamentals for Android Java Hooks
Frida’s JavaScript API provides powerful constructs for interacting with the Android Java runtime:
Java.perform(function() { ... });: The entry point for all Java-related manipulations.Java.use("package.ClassName");: Obtains a JavaScript wrapper for a Java class, allowing you to access its static and instance methods.$init: Used to hook constructors of a class.overload(...): Essential for targeting specific overloaded methods, differentiating them by their argument types.this.methodName.apply(this, arguments);orthis.methodName.call(this, arg1, arg2);: Used inside a hook to call the original implementation of the method, ensuring the app’s functionality isn’t broken.
Hooking Common Android Crypto APIs
Let’s explore essential hooks for prevalent Android cryptographic classes.
1. javax.crypto.Cipher
The Cipher class is central to encryption and decryption operations. By hooking its init, update, and doFinal methods, we can extract critical information like keys, IVs, and the data being processed.
Java.perform(function () {var Cipher = Java.use("javax.crypto.Cipher");Cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (opmode, key, params) {console.log("--- Cipher.init Called ---");console.log("Key Algorithm: " + key.getAlgorithm());console.log("Key Format: " + key.getFormat());if (key.getEncoded()) {console.log("Key Bytes (Base64): " + Java.use("android.util.Base64").encodeToString(key.getEncoded(), 0));}if (params !== null && params.$className === "javax.crypto.spec.IvParameterSpec") {var IvParameterSpec = Java.cast(params, Java.use("javax.crypto.spec.IvParameterSpec"));console.log("IV Bytes (Base64): " + Java.use("android.util.Base64").encodeToString(IvParameterSpec.getIV(), 0));}var opmodeStr = "";if (opmode === 1) opmodeStr = "ENCRYPT_MODE";else if (opmode === 2) opmodeStr = "DECRYPT_MODE";else opmodeStr = "UNKNOWN_MODE";console.log("Operation Mode: " + opmodeStr);return this.init(opmode, key, params);};Cipher.update.overload('[B').implementation = function (input) {console.log("--- Cipher.update Input (Base64) ---");console.log(Java.use("android.util.Base64").encodeToString(input, 0));var result = this.update(input);return result;};Cipher.doFinal.overload('[B').implementation = function (input) {console.log("--- Cipher.doFinal Input (Base64) ---");console.log(Java.use("android.util.Base64").encodeToString(input, 0));var result = this.doFinal(input);console.log("--- Cipher.doFinal Result (Base64) ---");console.log(Java.use("android.util.Base64").encodeToString(result, 0));return result;};});
2. java.security.MessageDigest
The MessageDigest class is used for hashing data. By hooking getInstance, update, and digest, we can identify the hashing algorithm, the data being hashed, and the final hash output.
Java.perform(function () {var MessageDigest = Java.use("java.security.MessageDigest");MessageDigest.getInstance.overload('java.lang.String').implementation = function (algorithm) {console.log("--- MessageDigest.getInstance Called ---");console.log("Algorithm: " + algorithm);return this.getInstance(algorithm);};MessageDigest.update.overload('[B').implementation = function (input) {console.log("--- MessageDigest.update Input (Base64) ---");console.log(Java.use("android.util.Base64").encodeToString(input, 0));return this.update(input);};MessageDigest.digest.overload().implementation = function () {var result = this.digest();console.log("--- MessageDigest.digest Result (Base64) ---");console.log(Java.use("android.util.Base64").encodeToString(result, 0));return result;};});
3. javax.crypto.spec.SecretKeySpec
SecretKeySpec is frequently used to construct secret keys from raw byte arrays. Hooking its constructor allows you to directly capture these raw key bytes.
Java.perform(function () {var SecretKeySpec = Java.use("javax.crypto.spec.SecretKeySpec");SecretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function (keyBytes, algorithm) {console.log("--- SecretKeySpec Constructor Called ---");console.log("Algorithm: " + algorithm);console.log("Key Bytes (Base64): " + Java.use("android.util.Base64").encodeToString(keyBytes, 0));return this.$init(keyBytes, algorithm);};});
4. java.security.Signature
The Signature class handles digital signing and verification. Hooking initSign, update, and sign helps reveal the private key used for signing, the data being signed, and the resulting signature.
Java.perform(function () {var Signature = Java.use("java.security.Signature");Signature.initSign.overload('java.security.PrivateKey').implementation = function (privateKey) {console.log("--- Signature.initSign Called ---");console.log("Private Key Algorithm: " + privateKey.getAlgorithm());console.log("Private Key Format: " + privateKey.getFormat());// Note: PrivateKey.getEncoded() might return null for some key types or providersif (privateKey.getEncoded()) {console.log("Private Key Bytes (encoded, Base64): " + Java.use("android.util.Base64").encodeToString(privateKey.getEncoded(), 0));} else {console.log("Private Key Bytes: Not directly extractable via getEncoded() for this key.");}return this.initSign(privateKey);};Signature.update.overload('[B').implementation = function (data) {console.log("--- Signature.update Data (Base64) ---");console.log(Java.use("android.util.Base64").encodeToString(data, 0));return this.update(data);};Signature.sign.overload().implementation = function () {var signature = this.sign();console.log("--- Signature.sign Result (Base64) ---");console.log(Java.use("android.util.Base64").encodeToString(signature, 0));return signature;};});
Executing Frida Hooks
To use these hooks, save the JavaScript code into a file (e.g., crypto_hooks.js). Then, attach Frida to your target Android application:
Attaching to a running application:
frida -U -l crypto_hooks.js com.example.targetapp
Spawning a new application instance:
frida -U -f com.example.targetapp -l crypto_hooks.js --no-pause
Replace com.example.targetapp with the package name of the application you are analyzing. As the application executes cryptographic operations, the Frida script will log the extracted data to your console.
Conclusion
Frida is an exceptionally powerful tool for dynamic analysis in Android security testing. By leveraging these essential hooks for common Java cryptographic APIs, you can efficiently uncover vital information such as encryption keys, IVs, plaintext data, and hash inputs that are often hidden during static analysis. This cheatsheet provides a solid foundation; remember to adapt and extend these hooks based on the specific cryptographic implementations you encounter in your target applications, potentially even delving into JNI hooks for native library analysis when needed. Happy hunting!
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 →