Hooking & Intercepting
📌What is hooking?
Hooking is the technique of intercepting and altering the functionality of functions or methods within an application or the Android operating system. For instance, by hooking a method in our app, we can modify its behavior by implementing our own logic.
📍How Frida Hooks into Apps
Frida can be injected into an app using two different approaches:
Injected Mode (Recommended)
Runs
frida-server
on your device.Allows you to attach to running apps without modifying the APK.
Embedded Mode
Requires modifying the APK manually.
You must inject the Frida Gadget (
.so
file) into the APK, repack it, and resign it.Useful for bypassing anti-debugging protections.
📍When to Run Your Script
Depending on when you want to start hooking the app, use the appropriate command:
If the app is already running (attach after objects are loaded):
frida -U -n package_name
If you want to start the app from the beginning (Before app initialization):
frida -U -f package_name -l script.js
📌What Does Interception Mean?
Interception is the process of hooking into a function at runtime to observe or modify its behavior. With Frida, this lets us:
See what arguments are passed to the function.
Modify those arguments before they’re used.
Run custom code when the function is called.
Change the return value before it’s given back to the app.
📍Basic Frida script
This is the skeleton we can use
// Ensure the script runs inside the Java environment Java.perform(function () { // Store the target class in a variable var varName = Java.use("package_name.class_name"); // Hook the onCreate method varName.onCreate.implementation = function (bundle) { // Log a message when the method is called console.log("onCreate called"); // Call the original onCreate method to avoid breaking the app this.onCreate(bundle); }; });
A short explanation of the functions
Java.perform(function() { ... })
Ensures that the script runs within the Java environment of the target app
Java.use("com.example.app.className")
Loads the specified Java class (
className
) from the target Android app so it can be manipulated.
.implementation
is used to hook and modify a method’s behavior at runtime. It allows us to intercept method calls, log data, modify parameters, or even change the method's return value.
📍In Java, methods can be overloaded, meaning multiple methods can have the same name but different parameters. For example, an Android Activity
class might have multiple onCreate
methods:
public void onCreate() { ... } // No parameters
public void onCreate(Bundle savedInstanceState) { ... } // Takes a Bundle
public void onCreate(Bundle savedInstanceState, String extra) { ... } // Two parameters
Since Frida needs to know exactly which method we are targeting, we use .overload(...)
to specify the parameter types.
Java.perform(function () {
var varName = Java.use("com.example.app.className");
// Hook the onCreate method (assuming it takes a Bundle as a parameter)
varName.onCreate.overload("android.os.Bundle").implementation = function (bundle) {
console.log("onCreate called");
this.onCreate(bundle);
};
});
📍Modifying a Method's Return Value
This script hooks into the randomDice()
method of the DiceGameFragment
class and changes its return value to 5
.
// Run the script within the Java VM context
Java.perform(function () {
// 1. Get a reference to the target class
var DiceGameFragment = Java.use("io.hextree.fridatarget.ui.DiceGameFragment");
// 2. Hook the 'randomDice' method
DiceGameFragment.randomDice.implementation = function () {
// Optional: Call the original method
this.randomDice();
// 3. Return a fixed value instead of the original result
return 5;
};
});