查看原文
其他

使用Frida打印Java类函数调用关系

无造 看雪学苑 2022-07-01

本文为看雪论坛文章

看雪论坛作者ID:无造



本文为看雪安卓高研3w班(8月班)优秀学员作品。


下面先让我们来看看讲师对学员学习成果的点评,以及学员的学习心得吧!


讲师点评

感谢Google的开源精神。通过对Android源码进行阅读,可以很快发现ART下类函数的四种调用:java调用java,java调用jni,jni调用java,jni调用jni;而java函数又有两种运行模式:interpreter模式和quick模式。
ART对不用的调用过程有着不同的处理逻辑。文章使用frida对ART下函数调用流程中的关键逻辑进行hook,同时结合对ART的定制,便可以得到APP运行过程中的执行轨迹,当然,对于函数调用过程中发生的参数传递以及返回结果等,事实上都可以通过对ART定制得到,进而能够构建一个动态分析沙箱。




学员感想


本题来自于3W班8月的第二题:请定制ART,完成对APP运行流程中所有的java类函数(包含java函数和jni函数)调用关系的trace。
对于Java层的单纯调用关系,可以比较方便的打印。参数的打印还是比较麻烦,Java对象的地址如何获取属性值等信息还是需要进一步深入研究。


ps. 题目附件请点击“阅读原文”下载。

好消息!!


现在看雪《安卓高级研修班》线下班 & 网课(12月班)开始同步招生啦!


以前没报上高研班的小伙伴赶快抓紧机会报名,升职加薪唾手可得!!





解题流程


根据之前的课程,可以得知有4种调用方式。其中java->java,java->jni在switch解释器下会通过DoCall方法。而jni->jni,jni->java则会通过反射相关的InvokeWithArgArray最后调用ArtMethod的Invoke方法。
 
这里考虑先使用frida验证运行逻辑,再修改源码刷机。
 
(这里编译源码将解释器改成Switch方便查看源码)


首先写个Demo,实现这几种调用


public int JavaCallJava(int i){ Log.i("javajnitrace","step1->JavaCallJava onEnter"); return JavaCallJni(0x1111);} public int JniCallJava(int i){ int javajnitrace = Log.i("javajnitrace", "step4->JniCallJava onEnter " + i); return 1;} public String JniCallJavaISS(int i, String s1, String s2){ int javajnitrace = Log.i("javajnitrace", "stepX->JniCallJavaISS onEnter " + i+" "+s1+" "+s2); JavaCallJavaIII(0x1111,0x2222,0x3333); return "JniCallJavaISS Called";} public int JavaCallJavaIII(int i, int j, int k){ Log.i("javajnitrace","stepX->JavaCallJavaIII onEnter"); //JavaCallJavaI17(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17); return i+j+k;}


extern "C"JNIEXPORT jint JNICALLJava_com_cwuzao_javajnitrace_MainActivity_JavaCallJni(JNIEnv *env, jobject thiz, jint i) { __android_log_print(4, "javajnitrace", "step2->JavaCallJni onEnter %0x", i); jclass class_MainActivity = env->FindClass("com/cwuzao/javajnitrace/MainActivity"); jmethodID method_JniCallJni = env->GetMethodID(class_MainActivity, "JniCallJni", "(I)I"); int callResult = env->CallIntMethod(thiz, method_JniCallJni, 0x2222); return callResult + 1;} extern "C"JNIEXPORT jint JNICALLJava_com_cwuzao_javajnitrace_MainActivity_JniCallJni(JNIEnv *env, jobject thiz, jint i) { __android_log_print(4, "javajnitrace", "step3->JniCallJni onEnter %0x",i); jclass class_MainActivity = env->FindClass("com/cwuzao/javajnitrace/MainActivity"); jmethodID method_JniCallJava = env->GetMethodID(class_MainActivity, "JniCallJava", "(I)I"); int callResult = env->CallIntMethod(thiz, method_JniCallJava, 0x3333); return callResult + 1;}


首先进行DoCall方法的HOOK


function DoCall_onEnter(args) { var addr_ArtMethod = args[2].add(8).readPointer(); allocPrettyMethod.writeByteArray(allocPrettyMethodInit); PrettyMethod(addr_ArtMethod_PrettyMethod, addr_ArtMethod, allocPrettyMethod, 0x100); var methodName = allocPrettyMethod.readCString(); if(methodName.indexOf(searchName) > -1){ var addr_Call_ArtMethod = args[0]; allocPrettyMethod.writeByteArray(allocPrettyMethodInit); PrettyMethod(addr_ArtMethod_PrettyMethod, addr_Call_ArtMethod, allocPrettyMethod, 0x100); var call_methodName = allocPrettyMethod.readCString(); console.log("DoCall:",methodName,"->", call_methodName); }}

DoCall: void com.cwuzao.javajnitrace.MainActivity$1.onClick(android.view.View) -> int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int)DoCall: int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int) -> int android.util.Log.i(java.lang.String, java.lang.String)DoCall: int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int) -> int com.cwuzao.javajnitrace.MainActivity.JavaCallJni(int)addr_InvokeWithArgArray onEnter-> int com.cwuzao.javajnitrace.MainActivity.JniCallJni(int)addr_InvokeWithArgArray onEnter-> int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int)DoCall: int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int) -> int android.util.Log.i(java.lang.String, java.lang.String)addr_InvokeWithArgArray onLeaveaddr_InvokeWithArgArray onLeave

DoCall只能打印java层发起的调用,Jni反射调用的并不走这个流程。


查看InvokeWithArgArray的HOOK


这里也可以HOOK ArtMethod的Invoke,参数基本上一样,而且ArtMethod的调用会多很多。

Interceptor.attach(addr_InvokeWithArgArray, { onEnter: function(args){ var addr_ArtMethod = args[1]; allocPrettyMethod.writeByteArray(allocPrettyMethodInit); PrettyMethod(addr_ArtMethod_PrettyMethod, addr_ArtMethod, allocPrettyMethod, 0x100); var methodName = allocPrettyMethod.readCString(); if(methodName.indexOf(searchName) > -1 ){ this.methodName = methodName; console.log("InvokeWithArgArray->",methodName, args[1], args[2], args[3], args[4]); } }, onLeave: function(retval){ } });

DoCall: int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int) -> int com.cwuzao.javajnitrace.MainActivity.JavaCallJni(int)addr_ArtMethod6Invoke onEnteraddr_InvokeWithArgArray onEnter-> int com.cwuzao.javajnitrace.MainActivity.JniCallJni(int)addr_ArtMethod6Invoke onEnteraddr_InvokeWithArgArray onEnter-> int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int)addr_ArtMethod6Invoke onEnterDoCall: int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int) -> int android.util.Log.i(java.lang.String, java.lang.String)

InvokeWithArgArray方法有个问题就是,我没有找到调用方的方法,虽然java->jni可以确定是哪里调用,但是jni->jni的可能会导致不知道上方是哪里调用的。

打印线程Tid


根据源码中这些方法都有Thread参数,所以尝试直接打印出tid,这样就算没有调用方,单一线程也只能同时运行一个方法。
 
源码中Thread可以直接调用GetTid获取线程ID,frida则可以根据内存分布,得知+0x10就是线程ID:

[3741]DoCall: void com.cwuzao.javajnitrace.MainActivity$1.onClick(android.view.View) -> int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int)[3741]DoCall: int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int) -> int android.util.Log.i(java.lang.String, java.lang.String)[3741]DoCall: int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int) -> int com.cwuzao.javajnitrace.MainActivity.JavaCallJni(int)[3741]addr_ArtMethod6Invoke onEnter->int com.cwuzao.javajnitrace.MainActivity.JavaCallJni(int)[3741]addr_ArtMethod6Invoke onEnter->int com.cwuzao.javajnitrace.MainActivity.JniCallJni(int)[3741]addr_ArtMethod6Invoke onEnter->int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int)[3741]DoCall: int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int) -> int android.util.Log.i(java.lang.String, java.lang.String)

打印参数


InvokeWithArgArray调用的参数


InvokeWithArgArray主要是va_list的处理,我这里先写Demo使用AS确定内存分布。之后读取参数就比较方便了。
 
这里打印参数就统一打印U32值,也可以根据方法名,判断参数类型,然后自定义打印。

Interceptor.attach(addr_InvokeWithArgArray, { onEnter: function(args){ var addr_ArtMethod = args[1]; allocPrettyMethod.writeByteArray(allocPrettyMethodInit); PrettyMethod(addr_ArtMethod_PrettyMethod, addr_ArtMethod, allocPrettyMethod, 0x100); var methodName = allocPrettyMethod.readCString(); if(methodName.indexOf("com.cwuzao.javajnitrace") > -1 ){ this.showResult = true; this.methodName = methodName; this.tid = args[0].readPointer().add(0x10).readU32(); var argscount = args[2].add(0x8).readU32(); console.log("["+this.tid+"]InvokeWithArgArray->",methodName, args[1], args[2], args[3], args[4]); // console.log("["+this.tid+"]args count:", argscount, "NumBytes:", args[2].add(0xC).readU32()); // console.log("addr_InvokeWithArgArray args[0]->", hexdump(args[2].add(0x10).readPointer())); var argspointer = args[2].add(0x10).readPointer(); for(var i=0; i< argscount; i++){ console.log("["+this.tid+"] args_", i+1,"->0x"+argspointer.add(i*4).readU32().toString(16)); } } }, onLeave: function(retval){ if(this.showResult){ console.log("["+this.tid+"]InvokeWithArgArray onLeave->",this.methodName, "\n result->0x"+retval.toString(16)); } } });

第一个参数是this指针,后续才是参数传递的值。


DoCall方法的参数打印


DoCall函数虽然可以打印调用关系,但是还没有为被调用方法初始化ShadowFrame,所以往下找了一些,最后HOOK了PerformCall里面的ArtInterpreterToInterpreterBridge和ArtInterpreterToCompiledCodeBridge。因为在DoCallCommon函数中初始化了ShadowFrame。
 
接下来就可以读取参数了,这里是通过修改参数,直接找到偏移进行读取,没有仔细理解ShadowFrame。

Interceptor.attach(addr_ArtInterpreterToInterpreterBridge, { onEnter: function(args){ var addr_ArtMethod = args[2].add(8).readPointer(); allocPrettyMethod.writeByteArray(allocPrettyMethodInit); PrettyMethod(addr_ArtMethod_PrettyMethod, addr_ArtMethod, allocPrettyMethod, 0x100); this.methodName = allocPrettyMethod.readCString(); if(this.methodName.indexOf(searchName) > -1){ this.showReuslt = true; // this.result = args[4]; this.result = args[2].add(0x3C) this.tid = args[0].add(0x10).readU32(); console.log("["+this.tid+"]ArtInterpreterToInterpreterBridge onEnter->",this.methodName); // var regcount = args[2].add(0x30).readU32(); // var registers_size_ = args[1].readU16(); var ins_size_ = args[1].add(0x2).readU16(); var outs_size_ = args[1].add(0x4).readU16(); // console.log("registers_size_->",registers_size_, "ins_size_->",ins_size_,"outs_size_->",outs_size_); //读取参数 var argsPointer = args[2].add(0x3C + 4*outs_size_); // console.log(hexdump(argsPointer)); for(var i=0; i< ins_size_; i++){ console.log("["+this.tid+"] args_"+i+"->0x"+argsPointer.add(i*4).readU32().toString(16)); } } }, onLeave: function(retval){ if(this.showReuslt){ console.log("["+this.tid+"]ArtInterpreterToInterpreterBridge onLeave->",this.methodName,"\n result->0x"+this.result.readU32().toString(16)); } }}); Interceptor.attach(addr_ArtInterpreterToCompiledCodeBridge, { onEnter: function(args){ var addr_ArtMethod = args[3].add(8).readPointer(); allocPrettyMethod.writeByteArray(allocPrettyMethodInit); PrettyMethod(addr_ArtMethod_PrettyMethod, addr_ArtMethod, allocPrettyMethod, 0x100); this.methodName = allocPrettyMethod.readCString(); if(this.methodName.indexOf(searchName) > -1){ this.showReuslt = true; this.result = args[4]; this.tid = args[0].add(0x10).readU32(); console.log("["+this.tid+"]ArtInterpreterToCompiledCodeBridge onEnter->",this.methodName, args[1],args[2],args[3]); var registers_size_ = args[3].add(0x30).readU32(); var argsPointer = args[3].add(0x3C);//这里并不是参数数量 for(var i=0; i< registers_size_; i++){ console.log("["+this.tid+"] args_"+i+"->0x"+argsPointer.add(i*4).readU32().toString(16)); } } }, onLeave: function(retval){ if(this.showReuslt){ console.log("["+this.tid+"]ArtInterpreterToCompiledCodeBridge onLeave->",this.methodName,"\n result->0x"+this.result.readU16().toString(16)); } }});

关于ArtInterpreterToCompiledCodeBridge的参数个数,不像ArtInterpreterToInterpreterBridge可以直接通过DexFile::CodeItem对象获取参数数量。所以直接读取的ShadowFrame的number_ofvregs打印所有寄存器值


打印查看效果


[22344]ArtInterpreterToInterpreterBridge onEnter-> void com.cwuzao.javajnitrace.MainActivity$1.onClick(android.view.View)[22344] args_0->0x1309e270[22344] args_1->0x1309da98[22344]DoCall: void com.cwuzao.javajnitrace.MainActivity$1.onClick(android.view.View) -> int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int)[22344]ArtInterpreterToInterpreterBridge onEnter-> int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int)[22344] args_0->0x13097278[22344] args_1->0x1234[22344]DoCall: int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int) -> int android.util.Log.i(java.lang.String, java.lang.String)[22344]DoCall: int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int) -> int com.cwuzao.javajnitrace.MainActivity.JavaCallJni(int)[22344]ArtInterpreterToCompiledCodeBridge onEnter-> int com.cwuzao.javajnitrace.MainActivity.JavaCallJni(int) 0x773f087068 0x0 0x7ff6a60400[22344] args_0->0x13097278[22344] args_1->0x1111[22344]InvokeWithArgArray-> int com.cwuzao.javajnitrace.MainActivity.JniCallJni(int) 0x773f087188 0x7ff6a5f868 0x7ff6a5f860 0x772585b765[22344] args_0->0x13097278[22344] args_1->0x2222[22344]InvokeWithArgArray-> int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int) 0x773f087128 0x7ff6a5eb78 0x7ff6a5eb70 0x772585b765[22344] args_0->0x13097278[22344] args_1->0x3333[22344]DoCall: int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int) -> void java.lang.StringBuilder.<init>()[22344]DoCall: int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int) -> java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)[22344]DoCall: int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int) -> java.lang.StringBuilder java.lang.StringBuilder.append(int)[22344]DoCall: int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int) -> java.lang.String java.lang.StringBuilder.toString()[22344]DoCall: int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int) -> int android.util.Log.i(java.lang.String, java.lang.String)[22344]InvokeWithArgArray onLeave-> int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int) result->0x1[22344]InvokeWithArgArray-> java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) 0x773f087158 0x7ff6a5eb78 0x7ff6a5eb70 0x772585d0e0[22344] args_0->0x13097278[22344] args_1->0x4444[22344] args_2->0x12c41b58[22344] args_3->0x12c41b78[22344]DoCall: java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) -> void java.lang.StringBuilder.<init>()[22344]DoCall: java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) -> java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)[22344]DoCall: java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) -> java.lang.StringBuilder java.lang.StringBuilder.append(int)[22344]DoCall: java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) -> java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)[22344]DoCall: java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) -> java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)[22344]DoCall: java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) -> java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)[22344]DoCall: java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) -> java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)[22344]DoCall: java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) -> java.lang.String java.lang.StringBuilder.toString()[22344]DoCall: java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) -> int android.util.Log.i(java.lang.String, java.lang.String)[22344]DoCall: java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) -> int com.cwuzao.javajnitrace.MainActivity.JavaCallJavaIII(int, int, int)ArtInterpreterToInterpreterBridge onEnter-> int com.cwuzao.javajnitrace.MainActivity.JavaCallJavaIII(int, int, int)[22344] args_0->0x13097278[22344] args_1->0x1111[22344] args_2->0x2222[22344] args_3->0x3333[22344]DoCall: int com.cwuzao.javajnitrace.MainActivity.JavaCallJavaIII(int, int, int) -> int android.util.Log.i(java.lang.String, java.lang.String)[22344]ArtInterpreterToInterpreterBridge onLeave-> int com.cwuzao.javajnitrace.MainActivity.JavaCallJavaIII(int, int, int) result->0x6666[22344]InvokeWithArgArray onLeave-> java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String) result->0x12c41d70[22344]InvokeWithArgArray onLeave-> int com.cwuzao.javajnitrace.MainActivity.JniCallJni(int) result->0x2ArtInterpreterToCompiledCodeBridge onLeave-> int com.cwuzao.javajnitrace.MainActivity.JavaCallJni(int) result->0x3[22344]ArtInterpreterToInterpreterBridge onLeave-> int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int) result->0x3[22344]ArtInterpreterToInterpreterBridge onLeave-> void com.cwuzao.javajnitrace.MainActivity$1.onClick(android.view.View) result->0x3

接下来就可以去修改源码刷机了


这里就偷懒了,刷机比较慢,只写调用,不读取参数了,只加了2行日志:

//reflection.ccstatic void InvokeWithArgArray(const ScopedObjectAccessAlreadyRunnable& soa, ArtMethod* method, ArgArray* arg_array, JValue* result, const char* shorty) //add const char* methodName = method->PrettyMethod().c_str(); if(strstr(methodName, "com.cwuzao.javajnitrace")){ LOG(ERROR)<< android::base::StringPrintf("[%d]InvokeWithArgArray %s", soa.Self()->GetTid(),methodName); } //addend} //interpreter_common.ccbool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data, JValue* result) { //add const char* methodName = shadow_frame.GetMethod()->PrettyMethod().c_str(); if(strstr(methodName, "com.cwuzao.javajnitrace")){ LOG(ERROR)<< android::base::StringPrintf("[%d]DoCall %s->%s", self->GetTid(), methodName, called_method->PrettyMethod().c_str()); } //addend}

[6825]DoCall void com.cwuzao.javajnitrace.MainActivity.<clinit>()->void java.lang.System.loadLibrary(java.lang.String)[6825]DoCall void androidx.appcompat.app.AppCompatActivity.onCreate(android.os.Bundle)->void androidx.appcompat.app.AppCompatActivity.onCreate(android.os.Bundle)[6825]DoCall void androidx.appcompat.app.AppCompatActivity.setContentView(int)->void androidx.appcompat.app.AppCompatActivity.setContentView(int)[6825]DoCall void com.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)->android.view.View androidx.appcompat.app.AppCompatActivity.findViewById(int)[6825]DoCall void com.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)->java.lang.String com.cwuzao.javajnitrace.MainActivity.stringFromJNI()[6825]DoCall void com.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)->void android.widget.TextView.setText(java.lang.CharSequence)[6825]DoCall void com.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)->android.view.View androidx.appcompat.app.AppCompatActivity.findViewById(int)[6825]DoCall void com.cwuzao.javajnitrace.MainActivity$1.<init>(com.cwuzao.javajnitrace.MainActivity)->void com.cwuzao.javajnitrace.MainActivity$1.<init>(com.cwuzao.javajnitrace.MainActivity)[6825]DoCall void com.cwuzao.javajnitrace.MainActivity$1.<init>(com.cwuzao.javajnitrace.MainActivity)->void java.lang.Object.<init>()[6825]DoCall void com.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)->void android.view.View.setOnClickListener(android.view.View$OnClickListener)[6825]DoCall void com.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)->android.view.View androidx.appcompat.app.AppCompatActivity.findViewById(int)[6825]DoCall void com.cwuzao.javajnitrace.MainActivity$2.<init>(com.cwuzao.javajnitrace.MainActivity)->void com.cwuzao.javajnitrace.MainActivity$2.<init>(com.cwuzao.javajnitrace.MainActivity)[6825]DoCall void com.cwuzao.javajnitrace.MainActivity$2.<init>(com.cwuzao.javajnitrace.MainActivity)->void java.lang.Object.<init>()[6825]DoCall void com.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)->void android.view.View.setOnClickListener(android.view.View$OnClickListener)[6825]DoCall void com.cwuzao.javajnitrace.MainActivity$1.onClick(android.view.View)->int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int)[6825]DoCall int android.util.Log.i(java.lang.String, java.lang.String)->int android.util.Log.i(java.lang.String, java.lang.String)[6825]DoCall int com.cwuzao.javajnitrace.MainActivity.JavaCallJni(int)->int com.cwuzao.javajnitrace.MainActivity.JavaCallJni(int)[6825]InvokeWithArgArray int com.cwuzao.javajnitrace.MainActivity.JniCallJni(int)[6825]InvokeWithArgArray int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int)[6825]DoCall int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int)->void java.lang.StringBuilder.<init>()[6825]DoCall int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int)->java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)[6825]DoCall int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int)->java.lang.StringBuilder java.lang.StringBuilder.append(int)[6825]DoCall java.lang.String java.lang.StringBuilder.toString()->java.lang.String java.lang.StringBuilder.toString()[6825]DoCall int android.util.Log.i(java.lang.String, java.lang.String)->int android.util.Log.i(java.lang.String, java.lang.String)[6825]InvokeWithArgArray java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String)[6825]DoCall java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String)->void java.lang.StringBuilder.<init>()[6825]DoCall java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String)->java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)[6825]DoCall java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String)->java.lang.StringBuilder java.lang.StringBuilder.append(int)[6825]DoCall java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String)->java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)[6825]DoCall java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String)->java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)[6825]DoCall java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String)->java.lang.String java.lang.StringBuilder.toString()[6825]DoCall java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String)->int android.util.Log.i(java.lang.String, java.lang.String)[6825]DoCall java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS(int, java.lang.String, java.lang.String)->int com.cwuzao.javajnitrace.MainActivity.JavaCallJavaIII(int, int, int)[6825]DoCall int com.cwuzao.javajnitrace.MainActivity.JavaCallJavaIII(int, int, int)->int android.util.Log.i(java.lang.String, java.lang.String)

这里打印反而有问题,刚调用函数打印调用和被调用方法名字一样?没理解什么原因,应该是哪里还要设置ShadowFrame,Frida那边正常,这边也能看到上一步调用,倒也不影响流程查看。
 
为了测试方便,这里加了过滤,直接hook strstr即可修改过滤字符。




- End -


看雪ID:无造

https://bbs.pediy.com/user-home-571058.htm

  *本文由看雪论坛 无造 原创,转载请注明来自看雪社区。



推荐文章++++

* Linux Kernel Pwn_1_Double fetch

Linux Kernel Pwn_0_kernel ROP与驱动调试

* 使用Frida分析动态注册jni函数绑定流程

* OneFuzz踩坑教程

* 最右sign-v2签名算法追踪及逆向还原






公众号ID:ikanxue
官方微博:看雪安全商务合作:wsc@kanxue.com



求分享

求点赞

求在看


“阅读原文”一起来充电吧!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存