Introduction to Frida Hook: Mastering Dynamic Analysis from Scratch

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

Leave a Comment