Unable to find JNI function with frida (android)

131 views Asked by At

I have the following class in android app:

package com.app.s;

public final class Api {
    public native int func(String str, String str2);

    ...
    ...
    static {
        try {
            System.loadLibrary("nativelib");
        } catch (UnsatisfiedLinkError e) {
            Log.e("lib", "fail:" + e.getMessage());
        }
    }
}

In libnativelib.so: function Java_com_app_s_Api_func is calling target_func

I'm trying to access target_func variables However I'm unable to locate the loaded module with frida

I've tried the following with frida:

try 1 - does not print the library name

var allModules = Process.enumerateModules()
for(var i=0;i<allModules.length;i++){ 
  console.log(allModules[i].name); 
}

try 2 - Error: java.lang.ClassNotFoundException: Didn't find class "Java_com_app_s_Api"

Java.perform(function() {
  var it = setInterval(function(){
    try{
      var hook = Java.use("Java_com_app_s_Api");
      console.log("info: hooking target class");

      hook.func.overload().implementation = function() {
                console.log("[+] func")

                var ret = this.func()
                console.log("[*] retval: " + ret)
                return ret

      }
    } catch(e) {
      console.log(e);
    }
  },200); // runs every 200milisecods
});

try 3 - doesn't print the functions in the library although they are being called

frida-trace -U -i "Java_*" -f <app>

try 4 (error) - loading findExportByName with dlopen frida snippet as suggested by Robert

   dlopen called with: libandroid.so
    dlopen called with: /system/lib64/libEGL.so
    dlopen called with: /system/lib64/libGLESv1_CM.so
    dlopen called with: /system/lib64/libGLESv2.so
    dlopen called with: /vendor/lib64/egl/libGLESv1_CM_emulation.so
    Process crashed: Trace/BPT trap
    
    ***
    *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    Build fingerprint: 'google/sdk_gphone64_x86_64/emu64xa:14/UE1A.230829.036.A1/11228894:userdebug/dev-keys'
    Revision: '0'
    ABI: 'x86_64'
    Timestamp: 2024-02-24 17:01:44.281739700+0000
    Process uptime: 4s
    Cmdline: com.app
    pid: 5917, tid: 5986, name: RenderThread  >>> com.app <<<
    uid: 10192
    signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
    Abort message: 'Failed to create context, error = EGL_NOT_INITIALIZED'

try 5

Java.perform(function() {
    var flag = false;
    try{
      Java.use("com.app.s.Api");
      var allModules = Process.enumerateModules()
        for(var i=0;i<allModules.length;i++){ 
            if(allModules[i].name.includes("nativelib")){
                console.log(allModules[i].name); 
                flag = true;
            }
        }
        if(!flag){
            console.log("not found");
        }
    } catch(e) {
      console.log(e);
    }
});

Do you have any idea what I'm missing?

1

There are 1 answers

4
Robert On

You have multiple problems:

Finding module libnativelib.so

libnativelib.so is only loaded when the Java class com.app.s.Api is loaded. This happens when this class is used for the first time.

Best way would be to hook the static {... part of that class (that would be the method <clinit>). Unfortunately I don't know if Frida does support hooking clinit method, some older versions seem to had problems doing so, not sure about recent versions.

Therefore My recommendation would be to hook in Java class java.lang.System the loadLibrary method to check when the library you are searching is loaded.

Once it is loaded you could directly install the hook for target_func.

Hooking Java_com_app_s_Api

Java_com_app_s_Api is not a Java class, it is the name of a native JNI function that implements a function that can be called from Java as it would be a Java function (which it is not). Therefore Java.use("Java_com_app_s_Api") will never work. What can work is Java.use("com.app.s.Api")

So you can try to create a Java hook for class com.app.s.Api for the JNI method func(String str, String str2) or you create an native hook using Interceptor.attach on the C function Java_com_app_s_Api_func (see example here).

Hook target_func

I assume target_func is not a function that is exported by the library. Therefore you have to use identify and use the address of the function. For doing so you need an external tool like Ghidra or IDA Pro to get the address of the function. At run-time you can then calculate the address you need to hook. More details can be found in the question and my answer to it frida hook native non exported functions

Sample code

In total I would recommend to you to follow the frida-snippet JNI hook example:

var moduleName = "libfoo.so"; 
var nativeFuncAddr = 0x1234; // get the address via Ghidra/IDA/...

Interceptor.attach(Module.findExportByName(null, "dlopen"), {
    onEnter: function(args) {
        this.lib = Memory.readUtf8String(args[0]);
        console.log("dlopen called with: " + this.lib);
    },
    onLeave: function(retval) {
        if (this.lib.endsWith(moduleName)) {
            console.log("ret: " + retval);
            var baseAddr = Module.findBaseAddress(moduleName);
            Interceptor.attach(baseAddr.add(nativeFuncAddr), {
                onEnter: function(args) {
                    console.log("[-] hook invoked");
                    console.log(JSON.stringify({
                        a1: args[1].toInt32(),
                        a2: Memory.readUtf8String(Memory.readPointer(args[2])),
                        a3: Boolean(args[3])
                    }, null, '\t'));
                }
            });
        }
    }
});