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

Posted LL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Frida打印Java类函数调用关系相关的知识,希望对你有一定的参考价值。

根据之前的课程,可以得知有4种调用方式。其中java->java,java->jni在switch解释器下会通过DoCall方法。而jni->jni,jni->java则会通过反射相关的InvokeWithArgArray最后调用ArtMethod的Invoke方法。

这里考虑先使用frida验证运行逻辑,再修改源码刷机。

(这里编译源码将解释器改成Switch方便查看源码 )

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

publicintJavaCallJava( inti ) { Log.i( "javajnitrace", "step1->JavaCallJava onEnter"); returnJavaCallJni( 0x1111); } publicintJniCallJava( inti ) { intjavajnitrace = Log.i( "javajnitrace", "step4->JniCallJava onEnter "+ i); return1; } publicString JniCallJavaISS( inti, String s1, String s2 ) { intjavajnitrace = Log.i( "javajnitrace", "stepX->JniCallJavaISS onEnter "+ i+ " "+s1+ " "+s2); JavaCallJavaIII( 0x1111, 0x2222, 0x3333); return"JniCallJavaISS Called"; } publicintJavaCallJavaIII( inti, intj, intk ) { Log.i( "javajnitrace", "stepX->JavaCallJavaIII onEnter"); //JavaCallJavaI17(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17); returni+j+k; }
extern"C" JNIEXPORT jint JNICALL Java_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"); intcallResult = env->CallIntMethod(thiz, method_JniCallJni, 0x2222); returncallResult + 1; } extern"C" JNIEXPORT jint JNICALL Java_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"); intcallResult = env->CallIntMethod(thiz, method_JniCallJava, 0x3333); returncallResult + 1; }
首先进行DoCall方法的HOOK

functionDoCall_onEnter( args) { varaddr_ArtMethod = args[ 2].add( 8).readPointer; allocPrettyMethod.writeByteArray(allocPrettyMethodInit); PrettyMethod(addr_ArtMethod_PrettyMethod, addr_ArtMethod, allocPrettyMethod, 0x100); varmethodName = allocPrettyMethod.readCString; if(methodName.indexOf(searchName) > -1){ varaddr_Call_ArtMethod = args[ 0]; allocPrettyMethod.writeByteArray(allocPrettyMethodInit); PrettyMethod(addr_ArtMethod_PrettyMethod, addr_Call_ArtMethod, allocPrettyMethod, 0x100); varcall_methodName = allocPrettyMethod.readCString; console.log( "DoCall:",methodName, "->", call_methodName); } }
DoCall: voidcom.cwuzao.javajnitrace.MainActivity$ 1.onClick(android.view.View) -> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) DoCall: intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) -> intandroid.util.Log.i(java.lang.String, java.lang.String) DoCall: intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) -> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJni( int) addr_InvokeWithArgArray onEnter-> intcom.cwuzao.javajnitrace.MainActivity.JniCallJni( int) addr_InvokeWithArgArray onEnter-> intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) DoCall: intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) -> intandroid.util.Log.i(java.lang.String, java.lang.String) addr_InvokeWithArgArray onLeave addr_InvokeWithArgArray onLeave
DoCall只能打印java层发起的调用,Jni反射调用的并不走这个流程。

查看InvokeWithArgArray的HOOK

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

Interceptor.attach(addr_InvokeWithArgArray, { onEnter: function( args) { varaddr_ArtMethod = args[ 1]; allocPrettyMethod.writeByteArray(allocPrettyMethodInit); PrettyMethod(addr_ArtMethod_PrettyMethod, addr_ArtMethod, allocPrettyMethod, 0x100); varmethodName = 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: intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) -> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJni( int) addr_ArtMethod6InvokeonEnter addr_InvokeWithArgArrayonEnter-> intcom.cwuzao.javajnitrace.MainActivity.JniCallJni( int) addr_ArtMethod6InvokeonEnter addr_InvokeWithArgArrayonEnter-> intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) addr_ArtMethod6InvokeonEnter DoCall: intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) -> intandroid.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: voidcom.cwuzao.javajnitrace.MainActivity$ 1.onClick(android.view.View) -> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) [ 3741]DoCall: intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) -> intandroid.util.Log.i(java.lang.String, java.lang.String) [ 3741]DoCall: intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) -> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJni( int) [ 3741]addr_ArtMethod6Invoke onEnter-> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJni( int) [ 3741]addr_ArtMethod6Invoke onEnter-> intcom.cwuzao.javajnitrace.MainActivity.JniCallJni( int) [ 3741]addr_ArtMethod6Invoke onEnter-> intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) [ 3741]DoCall: intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) -> intandroid.util.Log.i(java.lang.String, java.lang.String)
打印参数

InvokeWithArgArray调用的参数

InvokeWithArgArray主要是va_list的处理,我这里先写Demo使用AS确定内存分布。之后读取参数就比较方便了。

这里打印参数就统一打印U32值,也可以根据方法名,判断参数类型,然后自定义打印。

Interceptor.attach(addr_InvokeWithArgArray, { onEnter: function( args) { varaddr_ArtMethod = args[ 1]; allocPrettyMethod.writeByteArray(allocPrettyMethodInit); PrettyMethod(addr_ArtMethod_PrettyMethod, addr_ArtMethod, allocPrettyMethod, 0x100); varmethodName = allocPrettyMethod.readCString; if(methodName.indexOf( "com.cwuzao.javajnitrace") > -1){ this.showResult = true; this.methodName = methodName; this.tid = args[ 0].readPointer.add( 0x10).readU32; varargscount = 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)); varargspointer = args[ 2].add( 0x10).readPointer; for( vari= 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){ varaddr_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; // varregisters_size_ = args[ 1].readU16; varins_size_ = args[ 1].add( 0x2).readU16; varouts_size_ = args[ 1].add( 0x4).readU16; // console.log("registers_size_->",registers_size_, "ins_size_->",ins_size_,"outs_size_->",outs_size_); //读取参数 varargsPointer = args[ 2].add( 0x3C+ 4outs_size_); // console.log(hexdump(argsPointer)); for( vari= 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){ varaddr_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]); varregisters_size_ = args[ 3].add( 0x30).readU32; varargsPointer = args[ 3].add( 0x3C); //这里并不是参数数量 for( vari= 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打印所有寄存器值

XM外汇MT4 metatrader4service.net

[ 22344]ArtInterpreterToInterpreterBridge onEnter-> voidcom.cwuzao.javajnitrace.MainActivity$ 1.onClick(android.view.View) [ 22344] args_0-> 0x1309e270 [ 22344] args_1-> 0x1309da98 [ 22344]DoCall: voidcom.cwuzao.javajnitrace.MainActivity$ 1.onClick(android.view.View) -> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) [ 22344]ArtInterpreterToInterpreterBridge onEnter-> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) [ 22344] args_0-> 0x13097278 [ 22344] args_1-> 0x1234 [ 22344]DoCall: intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) -> intandroid.util.Log.i(java.lang.String, java.lang.String) [ 22344]DoCall: intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) -> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJni( int) [ 22344]ArtInterpreterToCompiledCodeBridge onEnter-> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJni( int) 0x773f0870680x00x7ff6a60400 [ 22344] args_0-> 0x13097278 [ 22344] args_1-> 0x1111 [ 22344]InvokeWithArgArray-> intcom.cwuzao.javajnitrace.MainActivity.JniCallJni( int) 0x773f0871880x7ff6a5f8680x7ff6a5f8600x772585b765 [ 22344] args_0-> 0x13097278 [ 22344] args_1-> 0x2222 [ 22344]InvokeWithArgArray-> intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) 0x773f0871280x7ff6a5eb780x7ff6a5eb700x772585b765 [ 22344] args_0-> 0x13097278 [ 22344] args_1-> 0x3333 [ 22344]DoCall: intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) -> voidjava.lang.StringBuilder.<init> [ 22344]DoCall: intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) -> java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String) [ 22344]DoCall: intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) -> java.lang.StringBuilder java.lang.StringBuilder.append( int) [ 22344]DoCall: intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) -> java.lang.String java.lang.StringBuilder.toString [ 22344]DoCall: intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) -> intandroid.util.Log.i(java.lang.String, java.lang.String) [ 22344]InvokeWithArgArray onLeave-> intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) result-> 0x1 [ 22344]InvokeWithArgArray-> java.lang.String com.cwuzao.javajnitrace.MainActivity.JniCallJavaISS( int, java.lang.String, java.lang.String) 0x773f0871580x7ff6a5eb780x7ff6a5eb700x772585d0e0 [ 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) -> voidjava.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) -> intandroid.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) -> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJavaIII( int, int, int) ArtInterpreterToInterpreterBridge onEnter-> intcom.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: intcom.cwuzao.javajnitrace.MainActivity.JavaCallJavaIII( int, int, int) -> intandroid.util.Log.i(java.lang.String, java.lang.String) [ 22344]ArtInterpreterToInterpreterBridge onLeave-> intcom.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-> intcom.cwuzao.javajnitrace.MainActivity.JniCallJni( int) result-> 0x2 ArtInterpreterToCompiledCodeBridge onLeave-> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJni( int) result-> 0x3 [ 22344]ArtInterpreterToInterpreterBridge onLeave-> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) result-> 0x3 [ 22344]ArtInterpreterToInterpreterBridge onLeave-> voidcom.cwuzao.javajnitrace.MainActivity$ 1.onClick(android.view.View) result-> 0x3
接下来就可以去修改源码刷机了

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

//reflection.cc staticvoidInvokeWithArgArray( constScopedObjectAccessAlreadyRunnable& soa, ArtMethod method, ArgArray arg_array, JValue result, constchar shorty) //add constchar 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.cc boolDoCall(ArtMethod called_method, Thread self, ShadowFrame& shadow_frame, constInstruction inst, uint16_tinst_data, JValue result) { //add constchar 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 voidcom.cwuzao.javajnitrace.MainActivity.<clinit>-> voidjava.lang.System.loadLibrary(java.lang.String) [ 6825]DoCall voidandroidx.appcompat.app.AppCompatActivity.onCreate(android.os.Bundle)-> voidandroidx.appcompat.app.AppCompatActivity.onCreate(android.os.Bundle) [ 6825]DoCall voidandroidx.appcompat.app.AppCompatActivity.setContentView( int)-> voidandroidx.appcompat.app.AppCompatActivity.setContentView( int) [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)->android.view.View androidx.appcompat.app.AppCompatActivity.findViewById( int) [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)->java.lang.String com.cwuzao.javajnitrace.MainActivity.stringFromJNI [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)-> voidandroid.widget.TextView.setText(java.lang.CharSequence) [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)->android.view.View androidx.appcompat.app.AppCompatActivity.findViewById( int) [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity$ 1.<init>(com.cwuzao.javajnitrace.MainActivity)-> voidcom.cwuzao.javajnitrace.MainActivity$ 1.<init>(com.cwuzao.javajnitrace.MainActivity) [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity$ 1.<init>(com.cwuzao.javajnitrace.MainActivity)-> voidjava.lang.Object.<init> [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)-> voidandroid.view.View.setOnClickListener(android.view.View$OnClickListener) [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)->android.view.View androidx.appcompat.app.AppCompatActivity.findViewById( int) [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity$ 2.<init>(com.cwuzao.javajnitrace.MainActivity)-> voidcom.cwuzao.javajnitrace.MainActivity$ 2.<init>(com.cwuzao.javajnitrace.MainActivity) [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity$ 2.<init>(com.cwuzao.javajnitrace.MainActivity)-> voidjava.lang.Object.<init> [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity.onCreate(android.os.Bundle)-> voidandroid.view.View.setOnClickListener(android.view.View$OnClickListener) [ 6825]DoCall voidcom.cwuzao.javajnitrace.MainActivity$ 1.onClick(android.view.View)-> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJava( int) [ 6825]DoCall intandroid.util.Log.i(java.lang.String, java.lang.String)-> intandroid.util.Log.i(java.lang.String, java.lang.String) [ 6825]DoCall intcom.cwuzao.javajnitrace.MainActivity.JavaCallJni( int)-> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJni( int) [ 6825]InvokeWithArgArray intcom.cwuzao.javajnitrace.MainActivity.JniCallJni( int) [ 6825]InvokeWithArgArray intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int) [ 6825]DoCall intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int)-> voidjava.lang.StringBuilder.<init> [ 6825]DoCall intcom.cwuzao.javajnitrace.MainActivity.JniCallJava( int)->java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String) [ 6825]DoCall intcom.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 intandroid.util.Log.i(java.lang.String, java.lang.String)-> intandroid.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)-> voidjava.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)-> intandroid.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)-> intcom.cwuzao.javajnitrace.MainActivity.JavaCallJavaIII( int, int, int) [ 6825]DoCall intcom.cwuzao.javajnitrace.MainActivity.JavaCallJavaIII( int, int, int)-> intandroid.util.Log.i(java.lang.String, java.lang.String)
这里打印反而有问题,刚调用函数打印调用和被调用方法名字一样?没理解什么原因,应该是哪里还要设置ShadowFrame,Frida那边正常,这边也能看到上一步调用,倒也不影响流程查看。

为了测试方便,这里加了过滤,直接hook strstr即可修改过滤字符。

以上是关于使用Frida打印Java类函数调用关系的主要内容,如果未能解决你的问题,请参考以下文章

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

JAVA如何调用C函数

如何使用 Frida 在 Android 中从挂钩的本机函数中打印变量

frida hook_RegisterNatives--使用frida打印so中动态注册的函数

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

使用jnitrace-engine和frida-compile