“
Frida, as the Swiss Army knife in the field of mobile security, is an essential tool for every security researcher. Today, we will briefly understand the basic principles and usage of Frida Hook, and get an initial grasp of this tool.
Introduction to Frida
What is Frida
Frida is a dynamic code analysis toolkit primarily used for:
- Dynamic hooking of applications
- Real-time modification of program behavior
- Analysis of application logic
- Bypassing security checks
Core Features
- Cross-platform: Supports Windows, macOS, Linux, Android, iOS
- Multi-language: Supports JavaScript, Python, C, etc.
- Easy to use: Simple API design, low learning curve
- Powerful functionality: Can hook almost all system calls and APIs
How Frida Works
Basic Architecture
Target Application ←→ Frida Server ←→ Frida Client ←→ Your Script
↓
Inject Process → Hook Function → Modify Behavior → Return Result
Hook Mechanism
1. Inject Frida Agent into the target process
2. Locate the target function address
3. Replace the function entry point
4. Execute custom logic
5. Call the original function or return custom value
Frida Installation and Configuration
1. Install Frida
# Install Frida client
pip install frida-tools
# Verify installation
frida --version
2. Android Environment Configuration
# Download Frida Server
# Download the corresponding version from https://github.com/frida/frida/releases
# Push to device
adb push frida-server /data/local/tmp/
adb shell chmod 755 /data/local/tmp/frida-server
# Start Frida Server
adb shell /data/local/tmp/frida-server &
3. Connect to Device
import frida
# Connect to device
device = frida.get_usb_device()
print(f"Device: {device}")
# List processes
processes = device.enumerate_processes()
for process in processes:
print(f"Process: {process.name} (PID: {process.pid})")
Basic Hook Examples
1. Hook Java Method
// Hook Java method example
Java.perform(function() {
// Hook the equals method of String class
var String = Java.use("java.lang.String");
String.equals.implementation = function(obj) {
console.log("String.equals called");
console.log("Parameter: " + obj);
// Call original method
var result = this.equals(obj);
console.log("Return value: " + result);
return result;
};
});
2. Hook Native Function
// Hook native function example
var libc = Module.findExportByName("libc.so", "strlen");
if (libc) {
Interceptor.attach(libc, {
onEnter: function(args) {
console.log("strlen called");
console.log("Parameter: " + Memory.readUtf8String(args[0]));
},
onLeave: function(retval) {
console.log("Return value: " + retval);
}
});
}
3. Hook System Call
// Hook system call example
var openat = Module.findExportByName("libc.so", "openat");
if (openat) {
Interceptor.attach(openat, {
onEnter: function(args) {
var path = Memory.readUtf8String(args[1]);
console.log("Opening file: " + path);
// Hide specific file
if (path.includes("su")) {
console.log("Hiding access to su file");
args[1] = Memory.allocUtf8String("/dev/null");
}
}
});
}
Useful Hook Techniques
1. Bypass Root Detection
// Bypass root detection
Java.perform(function() {
// Hook file existence check
var File = Java.use("java.io.File");
File.exists.implementation = function() {
var path = this.getAbsolutePath();
console.log("Checking file: " + path);
// Hide root-related files
if (path.includes("su") || path.includes("magisk")) {
console.log("Hiding root file: " + path);
return false;
}
return this.exists();
};
// Hook system property retrieval
var SystemProperties = Java.use("android.os.SystemProperties");
SystemProperties.get.overload("java.lang.String", "java.lang.String").implementation = function(key, def) {
console.log("Getting property: " + key);
// Fake root-related properties
if (key === "ro.debuggable") {
return "0";
}
if (key === "ro.secure") {
return "1";
}
return this.get(key, def);
};
});
2. Bypass SSL Pinning
// Bypass SSL pinning
Java.perform(function() {
// Hook X509TrustManager
var X509TrustManager = Java.use("javax.net.ssl.X509TrustManager");
X509TrustManager.checkClientTrusted.implementation = function(chain, authType) {
console.log("Bypassing client certificate check");
};
X509TrustManager.checkServerTrusted.implementation = function(chain, authType) {
console.log("Bypassing server certificate check");
};
X509TrustManager.getAcceptedIssuers.implementation = function() {
return Java.use("java.util.ArrayList").$new();
};
});
3. Monitor Network Requests
// Monitor network requests
Java.perform(function() {
// Hook OkHttp
var OkHttpClient = Java.use("okhttp3.OkHttpClient");
var Request = Java.use("okhttp3.Request");
// Hook Request.Builder
var RequestBuilder = Java.use("okhttp3.Request$Builder");
RequestBuilder.build.implementation = function() {
var request = this.build();
var url = request.url().toString();
console.log("HTTP Request: " + url);
return request;
};
});
Advanced Hook Techniques
1. Dynamic Class Loading
// Dynamic class loading
Java.perform(function() {
// Wait for class to load
Java.choose("com.example.TargetClass", {
onMatch: function(instance) {
console.log("Found target instance: " + instance);
// Hook instance method
instance.targetMethod.implementation = function() {
console.log("Target method called");
return this.targetMethod();
};
},
onComplete: function() {
console.log("Search complete");
}
});
});
2. Memory Operations
// Memory operations
Java.perform(function() {
// Read memory
var baseAddr = Module.getBaseAddress("libtarget.so");
var value = Memory.readU32(baseAddr.add(0x1000));
console.log("Memory value: " + value);
// Write to memory
Memory.writeU32(baseAddr.add(0x1000), 0x12345678);
// Allocate memory
var buffer = Memory.alloc(1024);
Memory.writeUtf8String(buffer, "Hello Frida");
});
3. Function Replacement
// Function replacement
var targetFunc = Module.findExportByName("libtarget.so", "target_function");
if (targetFunc) {
Interceptor.replace(targetFunc, new NativeCallback(function(arg1, arg2) {
console.log("Replaced function called");
console.log("Parameter 1: " + arg1);
console.log("Parameter 2: " + arg2);
// Return custom value
return 0x12345678;
}, 'int', ['int', 'int']));
}
Common Commands
1. Basic Commands
# List devices
frida-ls-devices
# List processes
frida-ps -U
# Attach to process
frida -U -f com.example.app -l script.js
# Start application
frida -U -f com.example.app -l script.js --no-pause
2. Advanced Commands
# Generate hook template
frida-trace -U -i "*open*" com.example.app
# Monitor system calls
frida-trace -U -j "*" com.example.app
# Export functions
frida -U com.example.app -e "console.log(Module.enumerateExports('libc.so'))"
Conclusion
This article mainly explains the official version of Frida. There are also some third-party modified versions based on certain features, which will not be elaborated here. Interested readers can explore them on their own, or I may write a follow-up article on how to customize your own Frida.
Key Points of This Article:
- Basic Principle: Process injection + Function hooking
- Core Functionality: Dynamically modify program behavior
- Application Scenarios: Security research, reverse analysis, vulnerability exploitation