首页
论坛
课程
招聘
[原创]使用Frida打印Java类函数调用关系
2020-11-3 09:56 8341

[原创]使用Frida打印Java类函数调用关系

2020-11-3 09:56
8341

前言

本题来自于3W班8月的第二题:请定制ART,完成对APP运行流程中所有的java类函数(包含java函数和jni函数)调用关系的trace。

 

对于Java层的单纯调用关系,可以比较方便的打印。参数的打印还是比较麻烦,Java对象的地址如何获取属性值等信息还是需要进一步深入研究。

解题流程

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

 

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

 

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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");
 
    int callResult = env->CallIntMethod(thiz, method_JniCallJni, 0x2222);
    return  callResult + 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");
    int callResult = env->CallIntMethod(thiz, method_JniCallJava, 0x3333);
    return  callResult + 1;
}

首先进行DoCall方法的HOOK

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
    }
}
1
2
3
4
5
6
7
8
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 onLeave
addr_InvokeWithArgArray onLeave

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

查看InvokeWithArgArray的HOOK

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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){
       }
   });
1
2
3
4
5
6
7
DoCall: int com.cwuzao.javajnitrace.MainActivity.JavaCallJava(int) -> int com.cwuzao.javajnitrace.MainActivity.JavaCallJni(int)
addr_ArtMethod6Invoke onEnter
addr_InvokeWithArgArray onEnter-> int com.cwuzao.javajnitrace.MainActivity.JniCallJni(int)
addr_ArtMethod6Invoke onEnter
addr_InvokeWithArgArray onEnter-> int com.cwuzao.javajnitrace.MainActivity.JniCallJava(int)
addr_ArtMethod6Invoke onEnter
DoCall: 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

1
2
3
4
5
6
7
[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值,也可以根据方法名,判断参数类型,然后自定义打印。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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打印所有寄存器值

打印查看效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
[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->0x2
ArtInterpreterToCompiledCodeBridge 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行日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//reflection.cc
static 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.cc
bool 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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[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即可修改过滤字符。


[公告] 欢迎大家踊跃尝试高研班11月试题,挑战自己的极限!

收藏
点赞2
打赏
分享
最新回复 (7)
雪    币: 8730
活跃值: 活跃值 (3864)
能力值: ( LV9,RANK:163 )
在线值:
发帖
回帖
粉丝
neilwu 活跃值 1 2020-11-4 11:14
2
0
漂亮
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_mnqvyswo 活跃值 2020-11-4 11:34
3
0
真棒,
雪    币: 8191
活跃值: 活跃值 (2762)
能力值: ( LV8,RANK:134 )
在线值:
发帖
回帖
粉丝
hanbingle 活跃值 2 2020-11-4 12:53
4
1
感谢Google的开源精神。通过对Android源码进行阅读,可以很快发现ART下类函数的四种调用:java调用java,java调用jni,jni调用java,jni调用jni;而java函数又有两种运行模式:interpreter模式和quick模式。ART对不用的调用过程有着不同的处理逻辑。文章使用frida对ART下函数调用流程中的关键逻辑进行hook,同时结合对ART的定制,便可以得到APP运行过程中的执行轨迹,当然,对于函数调用过程中发生的参数传递以及返回结果等,事实上都可以通过对ART定制得到,进而能够构建一个动态分析沙箱。
雪    币: 394
活跃值: 活跃值 (544)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
灯-等灯等灯~ 活跃值 2020-11-8 23:13
5
0

我在art/runtime/interpreter/interpreter_common.cc中修改bool DoCall函数,但是打印不出日志信息,使用frida  Hook strstr函数,我是在版本为8.1.0_r1版本修改的

文件头有引入android::base::StringPrintf

最后于 2020-11-9 09:55 被灯-等灯等灯~编辑 ,原因:
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_GNN 活跃值 2021-5-7 16:03
6
0
大侠,里面好多参数找不到在哪定义的,可以给发个demo吗
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_awgomyjn 活跃值 2021-5-19 10:24
7
0
大侠,你好,请问这里的“DoCall”方法是怎么Hook的
雪    币: 232
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
黑洞yyh 活跃值 2021-10-23 22:30
8
1
没头没尾。
游客
登录 | 注册 方可回帖
返回