Android Native Library Analysis
📌What are Native Libraries?
Native libraries are compiled code written in low-level languages like C or C++ that run directly on the hardware.
They offer better performance and lower overhead compared to Java or Kotlin, which run on the Java Virtual Machine (JVM).
In Android, developers use native libraries to optimize performance-critical code, such as image processing, encryption, or game engines.
🔧How Are Native Libraries Used in Android?
Writing Native Code
Native code is written in C or C++.
This is typically done using the NDK (Native Development Kit).
JNI (Java Native Interface)
JNI allows Java/Kotlin to call functions written in C/C++.
You write native methods in Java/Kotlin, then link them to implementations in C/C++.
JNIEXPORT jstring JNICALL Java_com_example_myapp_NativeExample_stringFromJNI(JNIEnv *env, jobject obj) { return (*env)->NewStringUTF(env, "Hello from C!"); }Code
This code defines a native C function that can be called from Java/Kotlin using JNI.
It takes three parameters:
envfor the JNI environment,thizfor the Java object, andstrfor a Java string (jstring).So if Java calls
stringFromJNI(), it gets"Hello from C!"from native C code.
Compiling Native Code
Native code is compiled into
.sofiles (shared objects).These
.sofiles are placed inside the APK under the/libfolder for each supported architecture (e.g.,armeabi-v7a,arm64-v8a).
🔄 How Java Calls Native Code
System.loadLibrary("native-lib")is used to loadlibnative-lib.so.
📍How to Reverse .so Files
.so FilesDecompile the APK
Use tools like apktool or JADX to extract the APK contents.
Navigate to the
/lib/folder where you’ll find.sofiles for each architecture.
Use Ghidra to Analyze
.soFilesHow to use Ghidra
Click file ⇒ new project ⇒ OK

Now, double-click on the file again.
Click on Yes and wait until the analysis is complete.
Click on Analyze again. After the analysis is complete, navigate to the left dropdown list Functions.

Focus on JNI Functions
Look for function names like
Java_com_example_myapp_ClassName_functionName.These are native methods called from Java/Kotlin.
Understand the Code
Ghidra shows the decompiled C-like code on the right and assembly code on the left.
You can rename variables, add comments, and trace function calls.
Use AI
Use AI tools to understand what the functions are doing.
📌Hooking the Native Functions
To hook native functions, we can use the Interceptor API. Here is the template for this:
Interceptor.attach: Attaches a callback to the specified function address. The targetAddress should be the address of the native function we want to hook.onEnter: This callback is called when the hooked function is entered. It provides access to the function arguments (args).onLeave: This callback is called when the hooked function is about to exit. It provides access to the return value (retval).
Always restart frida when you are hooking native functions or it will get messy.
📍When to use onEnter and when to use onLeave
onEnter and when to use onLeaveonEnter: When the function starts executingUse it when you want to:
Read or modify function arguments
Log or tamper with input values
Track call stacks, thread info, etc.
onLeave: When the function is about to returnUse it when you want to:
Read the return value
Modify (or "patch") the return value using
.replace(...)
Example use case:
📍Finding Function Addresses
There are several ways to do this. Let me show you some APIs to do this.
Using the Frida API:
Module.enumerateExports("sharedObjectName.so")This API lists all the exported symbols from a specified module.
It requires one argument: the name of the module (shared library or executable) from which you want to enumerate the exports.
Using the Frida API:
Module.getExportByName()The
Module.getExportByName(modulename, exportName)function fetches the address of the exported symbol with the specified name from the module (shared library). If you’re unsure which library contains your exported symbol, you can pass null.
Using the Frida API:
Module.findExportByName()Calculate the offset and add it to the
Module.getBaseAddress()(Base address)Using the Frida API:
Module.enumerateImports()It provides the imports of a module.
It’s important not to hardcode this address since it changes every time the application starts due to ASLR being enabled by default in Android.
📍Exports and Imports
Exports refer to the functions or variables a library provides for external use, such as the functions we use daily in programming languages like Python and C. Imports are functions or variables imported by our application.

📍Native Hooking Methodology (with Frida)
🔍 1. List All Exports of the Native Library
Goal: Identify the available functions that can be hooked in the native library (
libFridaEight.soin this case).
🎯 2. Identify the Target Function to Hook
Use the
namefrom the enumeration step to get the function’s address:
🪝 3. Hook the Function with Interceptor
Start with a basic
Interceptor.attach:
🧠 4. Understand Arguments and Return Value
If it’s a JNI function:
args[0]: JNIEnv pointerargs[1]: jobject (usuallythis)args[2+]: Function parameters
Explaintion
When you hook a JNI function (a native function from Java that calls C/C++ code), Frida gives you the arguments in
argslike this:That means the function receives:
JNIEnv *env→ helps work with Java stuff (like strings)jobject thiz→ reference to the Java object that called it (likethis)jstring input→ the actual Java string sent by the app
Now in Frida:
🔓 5. Reconstruct native logic to extract secrets
Last updated