Skip to content

[Frida Util] Add Support for Interceptor to Hook Native Methods #3384

@cpholguera

Description

@cpholguera

Follow-up from: #3359

The current script supports Java-level hooking using Frida’s Java API. This covers most use cases during mobile app penetration testing, especially when working with Java or Kotlin code. However, many critical security-related operations are implemented in native libraries, especially in apps that rely on custom cryptography, native obfuscation, or performance-critical code.

To handle these cases, the script must support Frida's Interceptor API, which allows hooking into native functions in shared libraries (e.g., .so files).

Why This Is Needed:

  • Many apps offload sensitive logic (e.g., crypto, certificate pinning, JNI wrappers) to native code.
  • Without native hooking, we miss a large surface area, including custom implementations not visible in the Java layer.
  • Full coverage during dynamic analysis and reverse engineering requires both Java and native hooks.

Proposed Behavior:

  • Allow hooks.js definitions to optionally target native functions.
  • New hook type for native entries, e.g.:
{
  category: "NATIVE_CRYPTO",
  hooks: [
    {
      native: true,
      module: "libcrypto.so",
      symbol: "AES_encrypt"
    }
  ]
}
  • The base script detects if native: true is present and uses Module.findExportByName and Interceptor.attach accordingly.

Benefits:

  • Enables analysis of hybrid apps and native-heavy implementations.
  • Complements Java hooks for deeper coverage.
  • Aligns with real-world testing needs where native code is commonly involved in critical operations.

This feature ensures the script is versatile enough for both high-level and low-level instrumentation during mobile assessments.


Use Case Example: MASTG-DEMO-0002

https://mas.owasp.org/MASTG/demos/android/MASVS-STORAGE/MASTG-DEMO-0002/MASTG-DEMO-0002/

In this demo, the app creates files in external storage using both Java APIs (ContentResolver.insert). However, internally, the system also calls native methods (open from libc.so). The current script mixes both Java and native hooks manually.

Java hook:

let ContentResolver = Java.use("android.content.ContentResolver");
ContentResolver.insert.overload('android.net.Uri', 'android.content.ContentValues').implementation = ...

Native hook:

Interceptor.attach(
    Process.getModuleByName('libc.so').getExportByName('open'),
    {
        onEnter: function(args) {
            const path = args[0].readCString();
            if (path.startsWith('/sdcard')) {
                console.log(path);
            }
        }
    }
);

Instead, we want to define this in hooks.js like:

var target = {
  category: "STORAGE",
  demo: "0002",
  hooks: [
    {
      class: "android.content.ContentResolver",
      method: "insert",
      overloads: [
        {
          args: ["android.net.Uri", "android.content.ContentValues"]
        }
      ]
    },
    {
      native: true,
      module: "libc.so",
      symbol: "open",
      filter: {
        arg1: ["/sdcard", "/storage/emulated"]
      },
      maxFrames: 15
    }
  ]
}

Behavior:

  • Native hooks are specified with native: true, a module, and a symbol.
  • Optional fields like filter and maxFrames provide control over when and how to log.
  • The base script handles attaching via Interceptor, decoding arguments, and printing stack traces.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions