分析了下某通信APP,發(fā)現(xiàn)他的數(shù)據(jù)發(fā)包參數(shù)中有三四個參數(shù)在so文件中生成返回;
通過ida動態(tài)調試了下APP的so,發(fā)現(xiàn)有些調試問題,老是阻斷,ida報錯的 tid:5056
這個問題沒能找到解決方法,有老哥知道了,感謝告知;
這個方法走不通,就來一波曲線救國,經(jīng)過一般折騰發(fā)現(xiàn)的registerNatives;
我本來的目的就是查找到動態(tài)注冊函數(shù)的地址,那么他的地址肯定會在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有四個參數(shù)
env是他的第一個參數(shù)(這個要注意)
第二個參數(shù)是他的Java類
第三個是要注冊的所以方法(在JNINativeMethod 的數(shù)組)
第四個是要注冊的方法數(shù)量
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方法的地址