Android App Penetration Testing & Frida Hooks

Frida for Android Penetration Testing: The Ultimate Setup Guide for Dynamic Instrumentation

Google AdSense Native Placement - Horizontal Top-Post banner

Introduction to Dynamic Instrumentation with Frida

Dynamic instrumentation has revolutionized Android application penetration testing, allowing security researchers to inspect and manipulate applications at runtime. Among the various tools available, Frida stands out as a powerful, versatile, and user-friendly toolkit. It enables reverse engineers and penetration testers to inject custom scripts into running processes on Android devices, providing unparalleled control over an application’s behavior. This guide will walk you through setting up Frida for Android penetration testing, from installing the necessary components to executing your first dynamic instrumentation scripts.

Prerequisites for Your Frida Setup

Before diving into the setup, ensure you have the following:

  • Rooted Android Device or Emulator: Frida operates by injecting into processes, which often requires root privileges to access system-level processes or inject into non-debuggable applications. An emulator like Genymotion or Android Studio’s AVD can also be used, provided it’s rooted.
  • Android Debug Bridge (ADB): Essential for interacting with your Android device (pushing files, forwarding ports, executing shell commands). Ensure it’s installed and configured in your system’s PATH.
  • Python 3: Frida’s client-side tools are primarily Python-based.
  • Workstation (Linux/macOS/Windows): Your primary machine where you’ll run Frida client scripts.

Step 1: Setting Up the Android Device (Frida Server)

1.1 Download the Frida Server Binary

Frida operates with a client-server architecture. The server runs on the target Android device, and the client (your workstation) communicates with it. You need to download the correct Frida server binary for your device’s architecture.

First, identify your Android device’s CPU architecture:

adb shell getprop ro.product.cpu.abi

Common architectures include arm64-v8a, armeabi-v7a, and x86_64.

Next, visit the Frida releases page on GitHub and download the frida-server-<version>-android-<arch>.xz file matching your device’s architecture and the latest Frida version. For example, frida-server-16.1.4-android-arm64.xz.

1.2 Push Frida Server to the Device

Extract the downloaded .xz file to get the frida-server executable. Then, push it to your Android device, typically to /data/local/tmp/, which is writable by apps and the shell.

adb push frida-server /data/local/tmp/

1.3 Set Permissions and Execute Frida Server

Grant execute permissions to the server binary and then run it. For rooted devices, you can run it directly. For unrooted devices with debuggable apps, you might need to use specific techniques like injecting into a debuggable app’s process context.

adb shellsu -c "chmod 755 /data/local/tmp/frida-server"adb shellsu -c "/data/local/tmp/frida-server &"

The & at the end runs the server in the background. You should not see any output if it starts successfully. If it fails, check for error messages. If using an emulator or a device where su is not available/necessary, you can sometimes run without su -c if /data/local/tmp is already executable, but usually, root is preferred for full functionality.

1.4 Forwarding Ports (Optional but Recommended)

To communicate with the Frida server from your workstation, it’s often convenient to forward the default Frida port (27042).

adb forward tcp:27042 tcp:27042

This allows your local machine to connect to the Frida server running on the Android device via localhost:27042.

Step 2: Setting Up the Workstation (Frida Client)

2.1 Install Frida Tools

Install the Frida client tools on your workstation using pip:

pip install frida-tools

2.2 Verify Installation

Once installed, you can verify that Frida is communicating with your device:

frida-ps -U

The -U flag tells Frida to connect to a USB device (which includes devices reachable via `adb forward`). If successful, you’ll see a list of processes running on your Android device.

If you encounter issues, ensure your frida-server is running on the device and adb forward is correctly set up.

Step 3: Basic Frida Usage – Your First Hook

Now that everything is set up, let’s perform a simple hook to demonstrate Frida’s power.

3.1 Attaching to an Application

To interact with an application, you need its package name or process ID. Let’s assume you want to hook into a sample application with the package name com.example.myapp.

You can get a list of running applications and their package names with frida-ps -Uai.

3.2 Creating a Simple Frida Script (JavaScript)

Frida scripts are written in JavaScript. Let’s create a script to intercept a common Android logging method, android.util.Log.i, to demonstrate a basic hook.

Save the following as hook_log.js:

Java.perform(function() {    // Get a reference to the Log class    var Log = Java.use('android.util.Log');    // Hook the 'i' method (for info messages)    Log.i.overload('java.lang.String', 'java.lang.String').implementation = function(tag, msg) {        // Log the original arguments        console.log("[Frida] Log.i called with tag: " + tag + ", message: " + msg);        // Call the original method        return this.i(tag, msg);    };    console.log("[Frida] Hooked android.util.Log.i successfully!");});

3.3 Injecting the Script

Use the frida -U -f <package_name> -l <script_file> --no-pause command to spawn the app, inject the script, and start it without pausing.

frida -U -f com.example.myapp -l hook_log.js --no-pause

Alternatively, if the app is already running:

frida -U -p $(frida-ps -U | grep com.example.myapp | awk '{print $1}') -l hook_log.js

Or by package name directly:

frida -U -l hook_log.js -n com.example.myapp

Once the app starts (or if it’s already running), you should see [Frida] Hooked android.util.Log.i successfully! in your terminal. As the application executes code that calls Log.i, you will see your custom log messages appearing in the terminal, demonstrating successful dynamic instrumentation.

Advanced Techniques and Common Use Cases

Bypassing SSL Pinning

One of the most common uses for Frida is bypassing SSL pinning. Generic SSL pinning bypass scripts are widely available and typically involve hooking methods in network libraries (like OkHttp, TrustManager) to prevent them from validating certificates.

// Example snippet for a generic SSL Pinning bypass Java.perform(function() {    console.log("[*] Starting SSL Pinning Bypass...");    var CertificateFactory = Java.use("java.security.cert.CertificateFactory");    var FileInputStream = Java.use("java.io.FileInputStream");    var BufferedInputStream = Java.use("java.io.BufferedInputStream");    var X509Certificate = Java.use("java.security.cert.X509Certificate");    var KeyStore = Java.use("java.security.KeyStore");    var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");    var SSLContext = Java.use("javax.net.ssl.SSLContext");    // ... full script involves hooking multiple classes/methods    // For demonstration, a simple hook for TrustManagerImpl might look like this:    try {        var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');        TrustManagerImpl.verifyChain.implementation = function(chain, authType, host, session) {            console.log("[*] TrustManagerImpl.verifyChain called. Bypassing...");            return; // Simply return, effectively bypassing validation        };        console.log("[*] TrustManagerImpl.verifyChain hooked.");    } catch (e) {        console.log("[-] TrustManagerImpl hook failed: " + e.message);    }    // ... more hooks for other SSL pinning implementations like OkHttp, etc.});

Hooking Specific Methods and Inspecting Arguments

You can hook into any Java method, inspect its arguments, modify them, and even change the return value. This is incredibly powerful for understanding application logic, manipulating data, or bypassing security checks.

Java.perform(function() {    var SomeClass = Java.use('com.example.myapp.SomeClass');    SomeClass.someMethod.implementation = function(arg1, arg2) {        console.log('[Frida] someMethod called!');        console.log('  arg1: ' + arg1);        console.log('  arg2: ' + arg2);        // Optionally modify arguments        // var newArg2 = "modified_" + arg2;        // console.log('  Modified arg2 to: ' + newArg2);        // Call the original method with original or modified arguments        var result = this.someMethod(arg1, arg2);        // Optionally modify return value        // var newResult = result + "_HOOKED";        console.log('  Original Return value: ' + result);        // return newResult;        return result;    };});

Conclusion

Frida provides an unparalleled level of control and insight into running Android applications. This guide has equipped you with the fundamental knowledge to set up your environment, install the Frida server, and execute basic dynamic instrumentation scripts. From bypassing SSL pinning to inspecting and manipulating method calls, Frida is an indispensable tool in any Android penetration tester’s arsenal. With practice and exploration, you’ll uncover even more sophisticated ways to leverage its capabilities for advanced 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