Android Software Reverse Engineering & Decompilation

Native Code Hacking: Injecting & Hooking .so Libraries with Frida Gadget

Google AdSense Native Placement - Horizontal Top-Post banner

Introduction

Dynamic instrumentation has revolutionized the field of software reverse engineering, offering unparalleled insight into runtime behavior. For Android applications, especially those heavily relying on native C/C++ libraries (.so files), Frida Gadget stands out as a powerful tool. Unlike the standard Frida server, Frida Gadget is a standalone library that can be injected directly into an application’s APK, enabling dynamic instrumentation without requiring root access on the target device. This expert-level guide will walk you through the process of integrating Frida Gadget, identifying native targets, and crafting sophisticated Frida scripts to hook and manipulate native functions within Android applications.

Prerequisites

Before diving into the practical steps, ensure you have the following tools and basic understanding:

  • Android Debug Bridge (ADB): For device interaction and file transfers.
  • Java Development Kit (JDK): Required for Apktool and signing.
  • Apktool: To decompile and recompile Android APKs.
  • Jadx-GUI or Ghidra/IDA Pro: For static analysis of APKs and .so libraries (optional but highly recommended for target identification).
  • Frida CLI Tools: For interacting with the Gadget.
  • Basic understanding of ARM assembly and C/C++ calling conventions (ABI).
  • A non-rooted Android device or emulator: Essential for demonstrating Frida Gadget’s key advantage.

Step 1: Preparing Frida Gadget and the Target APK

Downloading Frida Gadget

Frida Gadget comes in various architectures. You need to select the one matching your target application’s native libraries (e.g., arm64-v8a, armeabi-v7a). Download the appropriate frida-gadget.so from the official Frida releases page.

# Example for arm64-v8a
wget https://github.com/frida/frida/releases/download/16.1.4/frida-gadget-16.1.4-android-arm64.so.xz
unxz frida-gadget-16.1.4-android-arm64.so.xz
mv frida-gadget-16.1.4-android-arm64.so frida-gadget.so

Decompiling the APK

Use Apktool to decompile your target APK. This will extract its resources, including the AndroidManifest.xml and native libraries.

apktool d target_app.apk -o target_app_decompiled

Injecting Gadget into the APK

Place frida-gadget.so into the decompiled APK’s native library directory. For instance, if the app uses arm64-v8a, copy it to target_app_decompiled/lib/arm64-v8a/. Next, modify the AndroidManifest.xml to load the gadget. Locate the <application> tag and add android:extractNativeLibs="true" (if not already present) and a <meta-data> tag to instruct the application to load frida-gadget.so at startup.

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.TargetApp"
android:extractNativeLibs="true">
<meta-data android:name="frida.load" android:value="frida-gadget.so" />
...
</application>

Alternatively, you can manually load the gadget using JNI in the application’s main activity. However, the meta-data approach is often simpler for initial injection.

Recompiling and Resigning the APK

Now, recompile the APK and sign it with your own debug key. If you don’t have a debug key, generate one using keytool.

apktool b target_app_decompiled -o target_app_frida.apk
keytool -genkey -v -keystore debug.keystore -alias debug_alias -keyalg RSA -keysize 2048 -validity 10000
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore debug.keystore target_app_frida.apk debug_alias
zipalign -v 4 target_app_frida.apk target_app_frida_aligned.apk

Step 2: Identifying Native Targets

This crucial step involves understanding what native functions you want to hook. Use static analysis tools like Jadx-GUI or Ghidra to analyze the APK and its `.so` libraries. Look for:

  • JNI functions: Functions prefixed with Java_ (e.g., Java_com_example_app_NativeLib_verifyLicense).
  • Exported functions: Functions exposed by the native library, often related to security checks, cryptographic operations, or critical logic.
  • Strings: Search for interesting strings within the `.so` files that might hint at function names or important data.

For instance, let’s assume we’ve identified a function named nativeCheckEligibility within libnativelib.so that returns a boolean indicating user eligibility.

Step 3: Crafting Your Frida Hook Script

With Frida Gadget loaded, it acts as a listener. You’ll connect to it using the Frida CLI or Python scripts. Here’s how to craft a basic script to hook our hypothetical nativeCheckEligibility function.

Basic Native Function Hooking

Java.perform(function () {
// Find the base address of the native library
// Replace 'libnativelib.so' with the actual library name
const libnative_base = Module.findBaseAddress('libnativelib.so');
if (!libnative_base) {
console.log('[-] libnativelib.so not found');
return;
}

console.log('[+] libnativelib.so loaded at:', libnative_base);

// Offset of the target function. You'd get this from Ghidra/IDA.
// For example, if Ghidra shows it at 0x123456 relative to lib base.
const nativeCheckEligibility_offset = 0x123456;
const nativeCheckEligibility_addr = libnative_base.add(nativeCheckEligibility_offset);

console.log('[+] Hooking nativeCheckEligibility at:', nativeCheckEligibility_addr);

// Intercept the function
Interceptor.attach(nativeCheckEligibility_addr, {
onEnter: function (args) {
console.log('[*] Entering nativeCheckEligibility');
// Log arguments if known. For ARM64, args[0] to args[7] are registers.
// Example: If it takes an integer as first arg
// console.log('Arg 0:', args[0].toInt32());
},
onLeave: function (retval) {
console.log('[*] Exiting nativeCheckEligibility');
console.log('[+] Original return value:', retval.toInt32());
// Modify the return value to always be true (1)
retval.replace(ptr(1)); // For a boolean/integer return
console.log('[+] Modified return value to:', retval.toInt32());
}
});
});

Understanding Native ABI and Arguments

When hooking native functions, understanding the Application Binary Interface (ABI) for your target architecture (e.g., ARM64) is critical. Parameters are passed via registers (x0-x7 for ARM64) and then the stack. Return values are typically in x0. Frida’s args array in onEnter corresponds to these registers/stack locations. Static analysis is key to determining the correct function signature (return type, argument types, and count).

For functions with complex structures or strings, you might need to use Memory.readCString(), Memory.readByteArray(), or define custom NativeFunction signatures to correctly interpret arguments.

Step 4: Running the Instrumented App and Script

First, install the modified APK on your device:

adb install target_app_frida_aligned.apk

Now, launch the application. Frida Gadget will start a local server. You can connect to it using frida-cli:

frida -U -f com.example.targetapp --no-pause -l hook.js
  • -U: Connect to a USB device.
  • -f com.example.targetapp: Spawn the specified package name (replace with your app’s package).
  • --no-pause: Start the app immediately after spawning.
  • -l hook.js: Load your Frida script.

As the application runs and executes the nativeCheckEligibility function, your Frida script will intercept it. You’ll see the onEnter and onLeave messages, along with the original and modified return values, printed to your console.

Conclusion

Frida Gadget offers a robust and flexible solution for dynamic instrumentation of Android native code, especially valuable when root access is unavailable or undesirable. By carefully injecting the gadget, identifying target functions through static analysis, and crafting precise Frida scripts, reverse engineers and security researchers can gain deep insights into application behavior, bypass restrictions, and understand complex native logic. This technique empowers you to go beyond static analysis, observing and manipulating code execution in real-time, which is indispensable for advanced mobile security assessments and vulnerability 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