使用Frida列印Java類函數調用關係

2021-02-20 看雪學院

本文為看雪論壇文章

看雪論壇作者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對象的地址如何獲取屬性值等信息還是需要進一步深入研究。


好消息!!

現在看雪《安卓高級研修班》線下班 & 網課(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");        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]);                                             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));           }       }   });


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[2].add(0x3C)            this.tid = args[0].add(0x10).readU32();            console.log("["+this.tid+"]ArtInterpreterToInterpreterBridge onEnter->",this.methodName);                         var registers_size_ = args[1].readU16();            var ins_size_ = args[1].add(0x2).readU16();            var outs_size_ = args[1].add(0x4).readU16();                                     var argsPointer = args[2].add(0x3C + 4*outs_size_);                        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行日誌:
static void InvokeWithArgArray(const ScopedObjectAccessAlreadyRunnable& soa,                               ArtMethod* method, ArgArray* arg_array, JValue* result,                               const char* shorty)    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);  }  } bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,            const Instruction* inst, uint16_t inst_data, JValue* result) {    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());  }  }

[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即可修改過濾字符。

看雪ID:無造

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

  *本文由看雪論壇 無造 原創,轉載請註明來自看雪社區。

相關焦點

  • 使用frida hook插件化apk
    從代碼中分析也可知道,此apk是插件化apk,使用的是騰訊開源的插件化框架Shadow,感興趣的可以去了解下。既然已經找到真正的apk,那我們就需要定位到關鍵代碼地方。字符串定位從字符串中定位到有多個類滿足,此時一個一個去分析排查太耗時,接下來通過frida來枚舉出所有加載的類。
  • 從三道題目入門frida
    題目主要考察了以下知識點:1. frida java hook與靜態函數的主動調用2. Frida遍歷ClassLoader從而hook動態加載的dex的函數3. frida native hook去反調試ps. 題目附件請點擊「閱讀原文」下載。現在,看雪《安卓高級研修班(網課)》9月班開始招生啦!
  • 這恐怕是學習Frida最詳細的筆記(三)
    Java高級特性——反射查找調用各種API接口、JNI、frida/xposed原理的一部分這裡其實有一個伏筆,就是為什麼我們要trace artmethod,hook artmethod是因為有些so混淆得非常厲害,然後也就很難靜態分析看出so裡面調用了哪些java函數,也不是通過類似JNI的GetMethodID這樣來調用的。
  • 使用 Frida 來 hack 安卓 APP(一)
    有以下一些炫酷的事情:•             訪問進程內存•             在應用運行的時候覆蓋函數•             調用導入的類中的函數•             尋找堆上的對象實例,並且利用它們•             Hook,記錄以及攔截函數等等當然你也可以利用 debugger 來做上面的這些事情
  • 初識Frida--Android逆向之Java層hook (二)
    仔細分析,會發現在這一步中可能會遇到下面的問題:怎麼調用xor方法。java是強類型語言,javascript是弱類型語言,怎麼將javascript參數進行類型轉換並傳遞到java語言中。怎麼將javascript參數進行類型轉換並傳遞到java語言中?
  • Hook夢幻旅途之Frida
    它主要提供了功能簡單的python接口和功能豐富的js接口,使得hook函數和修改so編程化,值得一提的是接口中包含了主控端與目標進程的交互接口,由此我們可以即時獲取信息並隨時進行修改。使用frida可以獲取進程的信息(模塊列表,線程列表,庫導出函數),可以攔截指定函數和調用指定函數,可以注入代碼,總而言之,使用frida我們可以對進程模塊進行手術刀式剖析。
  • 記一次frida實戰——對某視頻APP的脫殼、hook破解、模擬抓包、協議分析一條龍服務
    既然是 frida 的一條龍服務,我們嘗試用 frida 來進行脫殼,這裡我們直接使用 frida-unpack(https://github.com/dstmath/frida-unpack)。 可以看到錯誤是因為在 libart.so 中不能通過 OpenMemory 的導出函數名找到它,這個十分奇怪,我們再寫個 frida 腳本把內存中 liart.so 的導出函數名和地址都列印出來看看有沒有 OpenMemory
  • frida跟蹤應用中所有運行在解釋模式的java函數
    "Computed-goto-based interpreter"239 : "Asm interpreter");240 return os;241 }如果想查看函數的調用,可以通過hook如下函數,並通過ShadowFrame參數使用shadow_frame.GetMethod()->PrettyMethod()獲取函數信息:
  • APP逆向神器之Frida【Android初級篇】
    說到逆向APP,很多人首先想到的都是反編譯,但是單看反編譯出來的代碼很難得知某個函數在被調用時所傳入的參數和它返回的值,極大地增加了逆向時的複雜度,有沒有什麼辦法可以方便地知道被傳入的參數和返回值呢?答案是有的,這個方法就是Hook,Hook的原理簡單地說就是用一個新的函數替代掉原來的函數,在這個新的函數中你想做什麼都可以,為所欲為。
  • 詳解Hook框架frida,讓你在逆向工作中效率成倍提升!
    一、frida簡介frida是一款基於python + javascript 的hook框架,可運行在androidioslinuxwinosx等各平臺,主要使用動態二進位插樁技術。本期「安仔課堂」,ISEC實驗室的彭老師為大家詳解frida,認真讀完這篇文章會讓你在逆向工作中效率成倍提升哦!
  • 使用msfvenom生成惡意APP並對該APK進行拆包分析
    我們再點進去 Payload.a(java.io.DataInputStream, java.io.OutputStream, java.lang.Object[])  。這裡對調用了兩次 Payload.a(java.io.DataInputStream) ,同樣打開這個方法看看。
  • 使用C++調用python3模塊中的類/函數詳細經驗
    /類方法(含傳參)0、導入要調用的python模塊//cpp PyObject* py_module = PyImport_ImportModule("test123.py"); if (py_module == NULL) { printf("import module failed\n"); // 列印模塊導入錯誤的原因
  • 零基礎java入門教程函數function實例化格式案例void返回值說明
    java基礎自學入門:函數:定義在類中的具有特定功能的一段獨立小程序有時候我們函數也稱為方法,平時我們聽到的函數也就是方法,方法也是函數,每個人的叫法不同,所以這裡要切記。老程式設計師別露餡喲。將這個部分定義成一個獨立的功能,方便與日後使用java中對功能的定義是通過行數的形式來體現的,需要定義功能,完成一個整數*3+5的運算並列印結果
  • Java中內部類到底有什麼用?
    普通內部類的語法大致就是這樣了。那麼,回到我們主題。內部類到底有什麼用?我們在實際項目中,應該如何使用內部類呢?Java中的閉包,閉包與內部類的關係作為一個程式設計師,即使你從來沒有使用過,你也應該聽說過閉包與回調。要從java,特別是j2ee的方向入手去講解閉包與回調,會比較困難。
  • Java基礎教程:Java之Object類,Objects類,Date類概念及使用!
    Object類概述java.lang.Object類是Java語言中的根類,即所有類的父類。它中描述的所有方法子類都可以使用。在對象實例化的時候,最終找的父類就是Object。如果一個類沒有特別指定父類, 那麼默認則繼承自Object類。
  • Python使用ctypes模塊調用DLL函數之傳遞結構體參數
    在Python語言中,可以使用ctypes模塊調用其它如C++語言編寫的動態連結庫DLL文件中的函數,在提高軟體運行效率的同時,也可以充分利用目前市面上各種第三方的DLL庫函數,以擴充Python軟體的功能及應用領域,減少重複編寫代碼、重複造輪子的工作量,這也充分體現了Python語言作為一種膠水語言所特有的優勢
  • 一起學JAVA——數組和函數
    之前我們介紹了java的數據類型、變量、流程控制等內容。今天我們高級數據類型——數組以及函數的作用。函數(方法)函數的定義函數就是一段有名字的代碼,可以完成某一特定功能。方法(函數)是java的最小代碼重用單位,方法(函數)是為了重用代碼。方法不能嵌套方法,不能在一個方法內部定義另外一個方法。可以在一個方法內部調用另外一個方法。
  • 一些經典Java面試題&答案解析 || 附《Effective Java》中文版
    start()用來啟動一個線程,當調用start方法後,系統才會開啟一個新的線程,進而調用run()方法來執行任務,而單獨的調用run()就跟調用普通方法是一樣的,已經失去線程的特性了。因此在啟動一個線程的時候一定要使用start()而不是run()。2、下列代碼執行結果是?
  • 阿里面試官:你了解Java Unsafe類嗎?|java|字符串|調用|實例化|...
    Unsafe有一個靜態的getUnsafe()方法,但是如果天真的以為調用該方法就可以的話,那你將遇到一個SecurityException異常,這是由於該方法只能在被信任的代碼中調用。  直接訪問內存的方法allocateMemorycopyMemoryfreeMemorygetAddressgetIntputInt  接下來是一些有趣的使用case  3、跳過構造初始化  allocateInstance方法可能是有用的,當你需要在構造函數中跳過對象初始化階段或繞過安全檢查又或者你想要實例化那些沒有提供公共構造函數的類時就可以使用該方法