frida动态获取registerNatives方法参数

分析了下某通信APP,发现他的数据发包参数中有三四个参数在so文件中生成返回;

通过ida动态调试了下APP的so,发现有些调试问题,老是阻断,ida报错的 tid:5056

这个问题没能找到解决方法,有老哥知道了,感谢告知;

这个方法走不通,就来一波曲线救国,经过一般折腾发现的registerNatives;

我本来的目的就是查找到动态注册函数的地址,那么他的地址肯定会在registerNatives方法中存在;

那么我们先看看这个register的方法的使用

写个简单的demo

const char *classPathName ="com/ex/jni_4/MainActivity";

JNINativeMethod method[] = {{"getString", "()Ljava/lang/String;",(void *) native_getString}};

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved){

JNIEnv *env =NULL;

    vm->GetEnv((void **) &env,JNI_VERSION_1_6);

    jclass jclass1 = env->FindClass(classPathName);

    if (jclass1 ==NULL){

return JNI_ERR;

    }

void* p = method;

    env->RegisterNatives(jclass1,method,1);

    env->DeleteLocalRef(jclass1);

    return JNI_VERSION_1_6;

}

registerNatives有四个参数

env是他的第一个参数(这个要注意)

第二个参数是他的Java类

第三个是要注册的所以方法(在JNINativeMethod 的数组)

第四个是要注册的方法数量

hook registerNatives方法的demo(这里就放出一个js)

var ModuleScanning = function (args) {

Process.enumerateModules({

onMatch: function (exp) {

if (exp.namein args) {

console.log("[*] Module:" + exp.name+ ",Address:" + exp.base);

}

},

onComplete: function () {

}

});

};

var RevealNativeMethods = function () {

console.log("native");

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= {};

var moduleDict= {};

function getNativeAddress(idx) {

return env.handle.readPointer().add(idx * pSize).readPointer();

}

// intercepting FindClass to populate Map

    Interceptor.attach(getNativeAddress(FindClassIndex), {

onEnter: function (args) {

jclassAddress2NameMap[args[0]]= args[1].readCString();

},

onLeave: function (args) {

}

});

// 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 methodName= methodsPtr.add(i* structSize ).readPointer();

var signature= methodsPtr.add(i* structSize+ pSize).readPointer();

var fnPtr= Memory.readPointer(methodsPtr.add(i* structSize+ pSize* 2));// void* fnPtr

                var jClass= jclassAddress2NameMap[args[0]].split('/');

var moduleName= DebugSymbol.fromAddress(fnPtr)['moduleName'];

console.log(JSON.stringify({

module: moduleName,// https://www.frida.re/docs/javascript-api/#debugsymbol

                    package: jClass.slice(0,-1).join('.'),

class: jClass[jClass.length- 1],

method: methodName.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

}));

moduleDict[moduleName]= "1";

}

},

onLeave: function (args) {

ModuleScanning(moduleDict);

}

});

};

Java.perform(RevealNativeMethods);

效果图

module是这个so的名称,我这边没能拿到,但不影响我的目标;后面我找到原因了在修改

typedef struct {

const char* name;

const char* signature;

void* fnPtr;

} JNINativeMethod;

这个是源码中定义的NINativeMethod的结构体

方法名,方法签名,方法地址

由于没有打印出该so的基址,

只能通过adb来看了

ps 命令拿到pid

cat /proc/(pid)/maps 



method":"ai","signature":"()Z","address":"0x244905ff

0x244905ff - 0xd1005000 = ida 中 ai方法的地址



引用

JNI调用和动态注册探索 · 饭先生 | blog

Android逆向之旅—抖音火山视频的Native注册混淆函数获取方法 | 尼古拉斯.赵四

你可能感兴趣的:(frida动态获取registerNatives方法参数)