你如何使用 frida 挂钩一个原生的剥离库?

Posted

技术标签:

【中文标题】你如何使用 frida 挂钩一个原生的剥离库?【英文标题】:How do you hook a native stripped library using frida? 【发布时间】:2020-02-17 20:30:05 【问题描述】:

在 java 内部,它从“something.so”调用本机函数:

public static native byte[] functionName(int i, byte[] bArr);

如您所见,此函数应该返回字节数组。所以我尝试了这个:

Interceptor.attach (Module.findExportByName ( "something.so", "functionName"), 
    onEnter: function (args) 
    
            console.log("entered");
            var ptr_data = env.getClassName(args[1]);
            var length = args[2];
            var data = Memory.readByteArray(ptr_data, length);
            console.log(data);
       
    );

但是 frida 不能返回任何结果。甚至没有打印“输入”。请注意,如果您使用 ida 打开,您将看不到名称“functionName”,因为它被剥离了 elf (.so) 我不知道“functionName”的这个位置在哪里,我想找到它,因为它包含很多垃圾代码。

还有其他方法可以使用 frida 找到它吗? 请写一个例子并与我分享。

【问题讨论】:

你的帖子让我很困惑。一方面,您在谈论类(通常表示“Java 类”) - 另一方面,您正在使用代码来挂钩本机(例如 C/C++,因此是非 Java)方法。 @Robert 感谢您解决这个问题。我编辑了帖子,我的意思是在java类中它调用了本机函数functionName 您应该提供更多详细信息 - 确切的类、方法和函数名称,否则您很可能得不到答案,因为不清楚问题出在哪里。 没有其他线索它被剥夺了精灵,你用ida看不到里面的任何东西 什么是“什么都不是”?通常你至少得到函数列表,可能没有名字。您尝试使用导出函数的任何人,因此我假设有一个导出方法列表。 【参考方案1】:

可以原生注册,不会导出,也就是说Module.enumerateExports看不到它

这个 sn-p 将挂钩 JNI RegisterNatives 并显示函数名称偏移量,您可以通过 Module.findBaseAddress('something.so').add(offset) 拦截该偏移量

registerNativeMethods 可用于对抗本机 .so 库的反逆向技术,例如尽可能隐藏符号,混淆导出的符号并最终在 JNI 桥上添加一些保护。 Find manually registered (obfuscated) native function address

var RevealNativeMethods = function() 
  var pSize = Process.pointerSize;
  var env = Java.vm.getEnv();
  var RegisterNatives = 215, FindClassIndex = 6; // search "215" @ https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html
  var jclassAddress2NameMap = ;
  function getNativeAddress(idx) 
    return env.handle.readPointer().add(idx * pSize).readPointer();
  
  // intercepting FindClass to populate Map<address, jclass>
  Interceptor.attach(getNativeAddress(FindClassIndex), 
    onEnter: function(args) 
      jclassAddress2NameMap[args[0]] = args[1].readCString();
    
  );
  // RegisterNative(jClass*, .., JNINativeMethod *methods[nMethods], uint nMethods) // https://android.googlesource.com/platform/libnativehelper/+/master/include_jni/jni.h#977
  Interceptor.attach(getNativeAddress(RegisterNatives), 
    onEnter: function(args) 
      for (var i = 0, nMethods = parseInt(args[3]); i < nMethods; i++) 
        /*
          https://android.googlesource.com/platform/libnativehelper/+/master/include_jni/jni.h#129
          typedef struct 
             const char* name;
             const char* signature;
             void* fnPtr;
           JNINativeMethod;
        */
        var structSize = pSize * 3; // = sizeof(JNINativeMethod)
        var methodsPtr = ptr(args[2]);
        var signature = methodsPtr.add(i * structSize + pSize).readPointer();
        var fnPtr = methodsPtr.add(i * structSize + (pSize * 2)).readPointer(); // void* fnPtr
        var jClass = jclassAddress2NameMap[args[0]].split('/');
        console.log('\x1b[3' + '6;01' + 'm', JSON.stringify(
          module: DebugSymbol.fromAddress(fnPtr)['moduleName'], // https://www.frida.re/docs/javascript-api/#debugsymbol
          package: jClass.slice(0, -1).join('.'),
          class: jClass[jClass.length - 1],
          method: methodsPtr.readPointer().readCString(), // char* name
          signature: signature.readCString(), // char* signature TODO Java bytecode signature parser  Z: 'boolean', B: 'byte', C: 'char', S: 'short', I: 'int', J: 'long', F: 'float', D: 'double', L: 'fully-qualified-class;', '[': 'array'  https://github.com/skylot/jadx/blob/master/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java
          address: fnPtr
        ), '\x1b[39;49;00m');
      
    
  );


Java.perform(RevealNativeMethods);

【讨论】:

以上是关于你如何使用 frida 挂钩一个原生的剥离库?的主要内容,如果未能解决你的问题,请参考以下文章

Frida - Windows 原生应用程序 - 读取 Wininet.h 公开的结构

Android使用Frida挂钩抽象类方法调用

Frida 服务器应用程序在与 Android 设备挂钩时崩溃

使用 Mingw32 安装 gmp 时如何修复无休止的“检查是不是可以剥离库”

从 Frida 的非主线程调用 API 来修改应用程序的 GUI

链接器如何在剥离的动态库中定位代码?