frida使用转载

2022-10-20  本文已影响0人  le_du

转的ling 大佬的

/*
首先进行初始化,初始化一些函数地址
hook功能
1. java层hook
    a. hookOneMethod yes
    b. hookOneClass yes
    c. hookAllMethod
    d. hookAllMethod2
    e. hook_loadLibrary0

2. jni层hook
    a. hook_JNIRegisterNatives
    b. hook_JNI_OnLoad

3. native层hook
    a. hook_dlopen
    b. hook_libc_kill_exit
    c. hook_system_property
    d. hook_android_log_print
    e. hook_call_function
    f. hook_call_array
    g. hook_ArtMethod_Invoke  yes
    h. hook_ArtInterpreterToInterpreterBridge yes
    h. hook_ArtInterpreterToCompiledCodeBridge  yes

4. objection的一些功能函数
    a. objection_getCurrentActivity yes
    b. objection_getActivities yes

5. 脱壳
    a. dexdump_DefineClass 
    b. dexdump_DexCache yes
    c. dexdump_Dex
    d. dexdump_LoadMethod

6. find功能
    a. find yes
    b. find2
    c. findClasses

7. 莫名其妙的崩溃原因
    1. 添加了native的backtrace

*/
//需要根据情况修改
var is_spawn = 0
var is_print_java_stackTrace = 1
var hook_java_enter = 0; // 默认java 调用完之后输出log,如果方法调用完之前崩溃,是看不到输出日志的。要在调用前输出日志,设置为1.
var is_print_native_stackTrace = 0
var is_print_args = 1; // print args
var is_print_retval = 1; // print retval

var run_env_num = 1;

var run_env = null;
if (run_env_num == 1) {
    run_env = "arm"
} else if (run_env_num == 2) {
    run_env = "arm64"
} else if (run_env_num == 3) {
    run_env = "x86"
}
////////////////////////////////
//不需要修改
var is_hooked = false;
var context = null;
var currentApplication = null;
var StringClass = null;
var Base64Class = null;
var ins_all = [];
var last_ins = null;
var frida_major_version = null;
var android_sdk_version = null;

var has_save_permission = false;

var module_libart = null;
var DefineClass_addr = null;
var LoadMethod_addr = null;
var PrettyMethod_addr = null;
var ArtMethodRegisterNative_addr = null;
var JNIRegisterNatives_addr = null
var is_print_art_param = 1; // 配置hook_ArtInterpreterToInterpreterBridge的参数和返回值,如果设置为0可以快速的查看函数调用
var is_print_art_retval = 1;
var ArtMethodInvoke_addr = null;
var ArtInterpreterToCompiledCodeBridge_addr = null;
var ArtInterpreterToInterpreterBridge_addr = null;
var artQuickToInterpreterBridge_addr = null;
var artQuickGenericJniTrampoline_addr = null;

// 打印native的参数
function print_native_log(user_log_list, tag) {
    if (tag == undefined) {
        tag = ""
    }
    var num = 20
    var start_symbol = "="
    var end_symbol = "-"
    var now = get_now()
    user_log_list.unshift(now)
    var log_start = new Array(num).join(start_symbol) + "[ThreadId:" + Process.getCurrentThreadId() + "]" + tag + " start!!!" + new Array(num).join(start_symbol)
    user_log_list.unshift(log_start)
    if (is_print_native_stackTrace) {
        // user_log_list.push(console.log('called from:\n'+Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'))
    }
    var log_end = new Array(num).join(end_symbol) + "[ThreadId:" + Process.getCurrentThreadId() + "]" + tag + " end!!!" + new Array(num).join(end_symbol)
    user_log_list.push(log_end)
    console.log(user_log_list.join("\n"));
}

function get_native_value(value_address, valuetype, index) {
    if (valuetype == undefined) {
        return "(" + valuetype + ")arg[" + index + "]";
    }
    valuetype = valuetype.replaceAll(" ", "")
    var name = "(" + valuetype + ")arg[" + index + "]";
    switch (valuetype) {
        case "int":
            name = name + ptr(value_address) + "=>" + value_address.readUInt()
            break
        case "long":
            name = name + ptr(value_address) + "=>" + value_address.readLong()
            break
        case "byte":
            name = name + ptr(value_address) + "=>" + value_address.readU8()
            break
        case "byte[]":
            if (value_address.readUInt() == 0x0) {
                // 空指针
                name = name + ptr(value_address) + "=>" + "bytes0x0:null"
            } else {
                var tmp_value_address = ptr(value_address.readUInt()).add(0xc)
                var byte_length = ptr(value_address.readUInt()).add(0x8).readUInt()
                // var result = tmp_value_address.readByteArray(byte_length)
                // name = name + ptr(value_address) + "=> byte_length:" +byte_length+"---result:"+hexdump(tmp_value_address,{length:byte_length})
                var array = []
                if (byte_length > 100) {
                    var print_byte_length = 100
                } else {
                    var print_byte_length = byte_length
                }

                for (var i = 0; i < print_byte_length; i++) {
                    array.push(tmp_value_address.add(i).readU8())
                }
                var canToString = checkByteArrayFromString(array);
                if (canToString) {
                    var param = Java.use("java.lang.String").$new(array)
                    var result = "[string]:" + param
                } else {
                    var param_hex = bytesToHex(array);
                    var result = "[hex]:0x" + param_hex
                }
                name = name + ptr(value_address) + "=> byte_length:" + byte_length + "---result:" + result
                // name = name + ptr(value_address) + "=> byte_length:" +byte_length+"---result:"+result+"\r\n"+hexdump(tmp_value_address)
            }
            break
        case "char":
            name = name + ptr(value_address) + "=>" + value_address.readU8()
            break
        case "float":
            // console.log(hexdump(value_address))
            name = name + ptr(value_address) + "=>" + value_address.readFloat()
            break
        case "boolean":
            name = name + ptr(value_address) + "=>" + value_address.readPointer()
            break
        case "java.lang.String":
            // try {
            // if (ptr(value_address).readU32() != 0x0) {
            //     var string_len = ptr(ptr(value_address).readU32()).add(0x8).readUInt() / 2
            //     console.log("String != 0x0"+"\r\n"+hexdump(value_address)+"\r\n"+hexdump(ptr(ptr(value_address).readU32()))+"\r\n"+hexdump(ptr(ptr(ptr(value_address).readU32()).readU32()))+"---len:"+string_len)
            //     name = name + ptr(value_address) + "=>" + ptr(ptr(value_address).readU32()).add(0x10).readCString(string_len)
            // } else if (ptr(value_address).readU32() == 0x8) {
            //     console.log("String == 0x8")
            //     name = name + ptr(value_address) + "=>" + ptr(value_address).add(0x10).readCString()
            // } else {
            // name = name + ptr(value_address) + "=>" + value_address
            // }
            // } catch (e) {
            //     console.log("error=======>" + e + " value_address=>" + value_address + "\r\n" + hexdump(value_address))
            // name = name + ptr(value_address) + "=>" + value_address
            // }
            
            try {
                if (ptr(value_address).readU32() == 0x0) {
                    // console.log("String == 0x8")
                    // console.log(hexdump(value_address))
                    // var string_len = ptr(ptr(value_address).readU32()).add(0x8).readUInt() / 2
                    // name = name + ptr(value_address) + "=>" + ptr(value_address).add(0x10).readCString()
                    name = name + ptr(value_address) + "=>string0x0:null"
                } else if (ptr(value_address).readU32() == 0x8) {
                    name = name + ptr(value_address) + "=>string0x8:" + "\r\n" + hexdump((value_address)) + "\r\n"
                }
                else if (ptr(value_address).readU32() != 0x0) {
                    // console.log(hexdump(ptr(ptr(value_address).readU32())))
                    var string_len = ptr(ptr(value_address).readU32()).add(0x8).readUInt() / 2
                    name = name + ptr(value_address) + "=>" + ptr(ptr(value_address).readU32()).add(0x10).readCString(string_len)
                } else {
                    // name = name + ptr(value_address) + "=>stringothers:" + value_address + "\r\n" + hexdump(ptr(ptr(value_address).readU32()))
                    name = name + ptr(value_address) + "=>stringothers:" + hexdump(value_address)
                }
            } catch (e) {
                console.log("error=======>" + value_address + "\r\n" + e + "   " + ptr(value_address.readUInt()) + "\r\n" + hexdump(value_address) + "\r\n")
                name = name + ptr(value_address) + "=>" + value_address
            }
            // name = name + ptr(value_address) + "=>" + "\r\n" + hexdump(value_address) + "\r\n" + "ptr(value_address).readU32()" + ptr(value_address).readU32()
            break
        case "void":
            break
        default:
            name = name + ptr(value_address) + "=>" + value_address
    }
    return name
}

// 获取当前时间
function get_now() {
    var date = new Date()
    var year = date.getFullYear()
    var month = date.getMonth()
    var day = date.getDate()
    var hour = date.getHours()
    var min = date.getMinutes()
    var seconds = date.getSeconds()
    var millsec = date.getMilliseconds()
    var result1 = [year, month, day]
    var result2 = [hour, min, seconds, millsec]
    return "[CurrentTime]" + result1.join("-") + " " + result2.join(":")
}
// 将java的参数和返回值组装打印
function print_java_log(user_log_list, tag) {
    Java.performNow(function () {
        if (tag == undefined) {
            tag = ""
        }
        var num = 20
        var start_symbol = "="
        var end_symbol = "-"
        var now = get_now()
        user_log_list.unshift(now)
        var log_start = new Array(num).join(start_symbol) + "[ThreadId:" + Process.getCurrentThreadId() + "]" + tag + " start!!!" + new Array(num).join(start_symbol)
        user_log_list.unshift(log_start)
        if (is_print_java_stackTrace) {
            user_log_list.push(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()))
        }
        var log_end = new Array(num).join(end_symbol) + "[ThreadId:" + Process.getCurrentThreadId() + "]" + tag + " end!!!" + new Array(num).join(end_symbol)
        user_log_list.push(log_end)
        console.log(user_log_list.join("\n"));
    })
}
function get_java_value(param, paramType, i) {
    var result = ""
    var name = null;
    if (i == undefined) {
        name = "(" + paramType + ")retval";
    } else {
        name = "(" + paramType + ")arg[" + i + "]";
    }
    if (param == null) {
        return name + " = null"
    }
    switch (paramType) {
        case "[C"://TODO
        case "[B":
            var canToString = checkByteArrayFromString(param);
            if (canToString) {
                result = name + " _bytearray= " + StringClass.$new(param)
            } else {
                var param_hex = bytesToHex(param);
                result = name + "_hex = " + param_hex
            }
            break;
        case "[I":
            result = name + "=" + JSON.stringify(param)
            // var canToString = checkByteArrayFromString(param);
            // if (canToString) {
            //     result = name + " _bytearray= " + StringClass.$new(param)
            // } else {
            //     var param_hex = bytesToHex(param);
            //     result = name + "_hex = " + param_hex
            // }
            break;
        case "java.util.Map":
        case "Ljava/util/Map;":
            var keys = param.keySet().toArray()
            var obj = {}
            for (var j = 0; j < keys.length; j++) {
                var value = param.get(keys[j])
                obj[keys[j]] = value.toString()
            }
            result = name + "=" + JSON.stringify(obj)
            break;
        case "java.util.List":
            var list = []
            for(var i = 0;i<param.length;i++){
                list.push(param[i])
            }
            result = name + "=" + new Array(list).join(",")
            break
        case "java.security.Key":
            var param_bytearray = param.getEncoded();
            var canToString = checkByteArrayFromString(param_bytearray);
            if (canToString) {
                result = name + "_key_str= " + StringClass.$new(param_bytearray)
            } else {
                var param_hex = bytesToHex(param_bytearray);
                result = name + "_key_hex = " + param_hex
            }
            break;
        case "java.security.spec.AlgorithmParameterSpec":
        case "Ljavax/crypto/spec/IvParameterSpec;":
            var IVClass = Java.use("javax.crypto.spec.IvParameterSpec");
            var ivObject = Java.cast(param, IVClass);
            var ivByte = ivObject.getIV();
            var canToString = checkByteArrayFromString(ivByte);
            if (canToString) {
                result = name + "_iv_str= " + StringClass.$new(ivByte)
            } else {
                var param_hex = bytesToHex(ivByte);
                result = name + "_iv_hex = " + param_hex
            }
            break;
        case "Ljavax/crypto/spec/SecretKeySpec;":
            var keyByte = param.getEncoded();
            var canToString = checkByteArrayFromString(keyByte);
            if (canToString) {
                result = name + "_key_str= " + StringClass.$new(keyByte)
            } else {
                var param_hex = bytesToHex(keyByte);
                result = name + "_key_hex = " + param_hex
            }
            break
        case "okio.BufferedSink":
        // result = name + "=" + param.buffer().readUtf8()
        // break
        default:
            result = name + "=" + param
            break;
    }
    return result
}
function isVisible(value) {
    if (value >= 32 && value <= 126) {
        return true;
    }
    return false;
}
function checkByteArrayFromString(bytearray) {
    var bytearray0 = Java.array("byte", bytearray);
    for (var i = 0; i < bytearray0.length; i++) {
        if (isVisible(bytearray[i]) == false) {
            return false;
        }
    }
    return true;
}
function bytesToHex(arr) {
    var str = "";
    var k, j;
    for (var i = 0; i < arr.length; i++) {
        k = arr[i];
        j = k;
        if (k < 0) {
            j = k + 256;
        }
        if (j < 16) {
            str += "0";
        }
        str += j.toString(16);
    }
    return str;
}
/*
hook一个方法,根据正则,过滤重载
hookOneMethod("java.net.URL.$init")
hookOneMethod("android.util.Base64.encodeToString")
hookOneMethod("javax.crypto.Cipher.doFinal","[B")
*/
function hookOneMethod(fullMethodName, overloadFilter) {
    /*
        hookOneMethod("java.net.URL.$init") // trace all method of $init
        hookOneMethod("java.net.URL.$init","java.lang.String") 
        hookOneMethod("java.net.URL.$init","java.net.URL,java.lang.String")
    */
    var split_length = fullMethodName.split(".").length;
    var method = fullMethodName.split(".")[split_length - 1];
    var classname = fullMethodName.slice(0, fullMethodName.length - method.length - 1); // -1是为了去掉那个点
    Java.performNow(function () {
        var tmpClass = Java.use(classname);
        if (tmpClass[method] == undefined) {
        } else {
            tmpClass[method].overloads.forEach(function (m) {
                var argumentTypes = m.argumentTypes;
                var returnType = m.returnType.name;
                var parameterStrArray = [];
                for (var tmpArg of argumentTypes) {
                    parameterStrArray.push(tmpArg["className"]);
                }
                if (overloadFilter != undefined && overloadFilter != parameterStrArray.join(",")) {
                    // console.log("your overloadFilter do not match")
                    return true
                } else {
                    console.log("hooking " + classname + "." + method + "(" + parameterStrArray.join(",") + ")");
                    m.implementation = function () {
                        var user_log_list = []
                        var user_log_list = ["called " + classname + "." + method + "(" + parameterStrArray.join(",") + ")"]
                        for (var i = 0; i < arguments.length; i++) {
                            if (is_print_args) {
                                // if (arguments[i] == null) continue
                                var tmp_java_value = get_java_value(arguments[i], parameterStrArray[i], i);
                                user_log_list.push(tmp_java_value)
                            }
                        }
                        if (hook_java_enter) {
                            // user_log_list.push("java called before hook!")
                            print_java_log(user_log_list, classname)
                        }
                        var retval = m.apply(this, arguments);
                        if (is_print_retval) {
                            var tmp_java_value = get_java_value(retval, returnType);
                            user_log_list.push(tmp_java_value)
                        }
                        if (!hook_java_enter) {
                            // user_log_list.push("java called over hook!")
                            print_java_log(user_log_list, classname)
                        }

                        return retval;
                    };
                }
            });
        }
    });
}

/*
hook一个类,根据正则,过滤方法名和重载
hookOneClass("javax.crypto.Cipher")
hookOneClass("javax.crypto.Cipher","doFinal")
hookOneClass("javax.crypto.Cipher","doFinal","[B")
*/
function hookOneClass(fullClassName, methodFilter, overloadFilter) {
    Java.performNow(function () {
        var toBeHookingMethods = []
        var tmpClass = Java.use(fullClassName)
        var method_init_all = tmpClass.class.getDeclaredConstructors();
        if (method_init_all.length > 0) {

            if (methodFilter == undefined) {
                toBeHookingMethods.push(fullClassName + ".$init")
            } else if (methodFilter != undefined && methodFilter == "$init") {
                toBeHookingMethods.push(fullClassName + "." + "$init")
            }
        }
        var method_all = tmpClass.class.getDeclaredMethods()
        for (var i = 0; i < method_all.length; i++) {
            var tmpMethod = method_all[i]
            var tmpMethodName = tmpMethod.getName()
            if (methodFilter != undefined && tmpMethodName.indexOf(methodFilter) != -1) {
                toBeHookingMethods.push(fullClassName + "." + tmpMethodName)
            } else if (methodFilter == undefined) {
                toBeHookingMethods.push(fullClassName + "." + tmpMethodName)
            }
        }
        toBeHookingMethods = Array.from(new Set(toBeHookingMethods))
        console.log("[traceOneClass]toBeHookingMethods.length=", toBeHookingMethods.length)
        for (var i = 0; i < toBeHookingMethods.length; i++) {
            var method = toBeHookingMethods[i]
            hookOneMethod(method, overloadFilter)
        }
    })
}
function query(classname, method) {
    // query("Base64")
    // query("Cipher","doFinal")
    if (frida_major_version < 14) {
        console.log("frida major version must >= 14")
        return
    }
    var filterPattern = "*Base64*!*encode*";
    var groups = null;
    if (classname == undefined && method == undefined) {
        console.log("please enter classname or method");
        return groups;
    }
    if (!classname) {
        classname = "*";
    }
    if (!method) {
        method = "*";
    }
    var filterPattern = "*" + classname + "*" + "!" + "*" + method + "*";
    Java.performNow(function () {
        groups = Java.enumerateMethods(filterPattern);
    });
    return groups;
}

function find(classname, method) {
    /*
        find("*.Cipher") // find all classes endswith .Cipher
        find("","doFinal") // find all methods equal doFinal
        find("*Base64*","*encode*") // find all classes match Base64 and methods match encode
    */
    var groups = query(classname, method)
    if (groups != "") {
        for (var group of groups) {
            var classes = group["classes"];
            for (var cls of classes) {
                var classname = cls["name"];
                var methods = cls["methods"];
                console.log("found class => " + classname);
                for (var method of methods) {
                    console.log("found method => " + classname + "." + method);
                }
                console.log("found " + methods.length + " methods");
            }
        }
        console.log("search finished");
    } else {
        console.log("search finished and found 0 method");
    }
}
function hookAllMethod(classnameFilter, methodFilter, overloadFilter) {
    /*
        hookAllMethod2("Base64")  // trace all class match Base64
        hookAllMethod2("","encode","[B,int") // trace all class and method equals encode and overload equals [B,int
        hookAllMethod2("Base64","encode","[B,int") // trace  class match Base64 and method match encode and overload equals [B,int
    */
    var groups = query(classnameFilter, methodFilter)
    if (groups != "") {
        for (var group of groups) {
            var classes = group["classes"];
            for (var cls of classes) {
                var classname = cls["name"];
                var methods = cls["methods"];
                for (var method of methods) {
                    var fullMethodName = classname + "." + method
                    console.log("string=>" + fullMethodName.toString())
                    try {
                        hookOneMethod(fullMethodName.toString(), overloadFilter);
                    } catch (e) {

                    }
                }
            }
        }
    } else {
        console.log("search finished and found 0 method");
    }
}

// objection的获取当前Activity

function R(name, type) {
    // const context = getApplicationContext();
    return context.getResources().getIdentifier(name, type, context.getPackageName());
}
function objection_getCurrentActivity() {
    Java.performNow(function () {
        const activityThread = Java.use("android.app.ActivityThread");
        const activity = Java.use("android.app.Activity");
        const activityClientRecord = Java.use("android.app.ActivityThread$ActivityClientRecord");

        const currentActivityThread = activityThread.currentActivityThread();
        const activityRecords = currentActivityThread.mActivities.value.values().toArray();
        let currentActivity;

        for (const i of activityRecords) {
            const activityRecord = Java.cast(i, activityClientRecord);
            if (!activityRecord.paused.value) {
                currentActivity = Java.cast(Java.cast(activityRecord, activityClientRecord).activity.value, activity);
                break;
            }
        }

        if (currentActivity) {
            console.log(currentActivity.$className)
            const fm = currentActivity.getFragmentManager();
            const fragment = fm.findFragmentById(R("content_frame", "id"));
            console.log(fragment.$className)
        }
    })
}

// objection的获取所有的Activities
function objection_getActivities() {
    Java.performNow(function () {
        const packageManager = Java.use("android.content.pm.PackageManager");
        const GET_ACTIVITIES = packageManager.GET_ACTIVITIES.value;
        var ActivityThreadClass = Java.use("android.app.ActivityThread");
        var context = ActivityThreadClass.currentActivityThread().getApplication().getApplicationContext()

        context.getPackageManager().getPackageInfo(context.getPackageName(), GET_ACTIVITIES).activities.value.map((activityInfo) => {
            console.log(activityInfo.name.value)
        })
    })
}
// objection的获取所有的Services
function objection_getServices() {
    Java.performNow(function () {
        var ActivityThreadClass = Java.use("android.app.ActivityThread");
        var ArrayMapClass = Java.use("android.util.ArrayMap");
        var PackageManagerClass = Java.use("android.content.pm.PackageManager");
        var GET_SERVICES = PackageManagerClass.GET_SERVICES.value;
        var currentApplication = ActivityThreadClass.currentApplication(); // not using the helper as we need other variables too
        var context = currentApplication.getApplicationContext();
        var services = [];
        currentApplication.mLoadedApk.value.mServices.value.values().toArray().map(function (potentialServices) {
            Java.cast(potentialServices, ArrayMapClass).keySet().toArray().map(function (service) {
                services.push(service.$className);
            });
        });
        services = services.concat(context.getPackageManager().getPackageInfo(context.getPackageName(), GET_SERVICES).services.value.map(function (activityInfo) {
            console.log("find Service => " + activityInfo.name.value)
            return activityInfo.name.value;
        }));
    })
}
// objection的跳转Activity界面
function objection_startActivity(activityName) {
    // https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_NEW_TASK
    Java.performNow(function () {
        var FLAG_ACTIVITY_NEW_TASK = 0x10000000; // starts an Android activity
        var IntentClass = Java.use("android.content.Intent"); // Get the Activity class's .class
        var newActivity = Java.use(activityName);
        var newIntent = IntentClass.$new(context, newActivity.class);
        newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(newIntent);
    })
}
// objection的启动Service
function objection_startService(serviceName) {
    // https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_NEW_TASK
    Java.performNow(function () {
        var FLAG_ACTIVITY_NEW_TASK = 0x10000000; // starts an Android activity
        var IntentClass = Java.use("android.content.Intent"); // Get the Activity class's .class
        var newService = Java.use(serviceName);
        console.log(newService.$className)
        var newIntent = IntentClass.$new(context, newService.class);
        newIntent.setFlags(FLAG_ACTIVITY_NEW_TASK);
        context.startService(newIntent);
    })
}

/*
sslpinning 仅对系统的checkServerTrusted以及标准ok3的check进行hook,无法对抗混淆的以及其它的
*/
function objection_sslpinning_disable_all() {
    sslpinning_disable_system()
    sslpinning_disable_okhttp3()
}

function sslpinning_disable_system() {
    Java.performNow(function () {
        var PlatformClass = Java.use("com.android.org.conscrypt.Platform")
        var targetMethodName = "checkServerTrusted"
        var overloadsLength = PlatformClass[targetMethodName].overloads.length;
        for (var i = 0; i < overloadsLength; ++i) {
            PlatformClass[targetMethodName].overloads[i].implementation = function () {
                console.log("com.android.org.conscrypt.Platform.checkServerTrusted->i=" + i + " arguments=" + JSON.stringify(arguments))
            }
        }
    })
}

function sslpinning_disable_okhttp3() {
    Java.performNow(function () {
        var CertificatePinnerClass = Java.use("okhttp3.CertificatePinner")
        var targetMethodName = "check"
        var overloadsLength = CertificatePinnerClass[targetMethodName].overloads.length;
        for (var i = 0; i < overloadsLength; ++i) {
            CertificatePinnerClass[targetMethodName].overloads[i].implementation = function () {
                console.log("okhttp3.CertificatePinner.check->i=" + i + " arguments=" + JSON.stringify(arguments))
            }
        }
    })
}
/*
hook root检测,但是仍然不全
*/
function objection_root_disable_all() {
    root_disable_testKeysCheck()
    root_disable_execSuCheck()
    root_disable_fileExistsCheck()
}

function root_disable_testKeysCheck() {
    Java.performNow(function () {
        var JavaString = Java.use("java.lang.String");
        JavaString.contains.implementation = function (name) {
            //这个太局限了
            if (name !== "test-keys") {
                return this.contains.call(this, name);
            } else {
                return false
            }
        };
    })
}

function root_disable_execSuCheck() {
    Java.performNow(function () {
        var JavaRuntime = Java.use("java.lang.Runtime");
        var iOException = Java.use("java.io.IOException");
        JavaRuntime.exec.overload("java.lang.String").implementation = function (command) {
            if (command.endsWith("su")) {
                console.log("called endsWith su")
            } // call the original method
            if (command.indexOf("su") != -1) {
                console.log("called indexOf su")
            }
            return this.exec.overload("java.lang.String").call(this, command);
        };
    })
}

function root_disable_fileExistsCheck() {
    Java.performNow(function () {
        var commonPaths = ["/data/local/bin/su", "/data/local/su", "/data/local/xbin/su", "/dev/com.koushikdutta.superuser.daemon/", "/sbin/su", "/system/app/Superuser.apk", "/system/bin/failsafe/su", "/system/bin/su", "/system/etc/init.d/99SuperSUDaemon", "/system/sd/xbin/su", "/system/xbin/busybox", "/system/xbin/daemonsu", "/system/xbin/su"];
        var JavaFile = Java.use("java.io.File");
        JavaFile.exists.implementation = function () {
            var filename = this.getAbsolutePath();
            if (commonPaths.indexOf(filename) >= 0) {
                console.log("called JavaFile exists =>" + filename)
            }
            return this.exists.call(this);
        }
    })
}

// 获取当前app的包名
function getPackageName() {
    var packageName = null;
    Java.performNow(function () {
        if (is_spawn) {
            packageName = get_self_process_name();
        } else {
            packageName = context.getPackageName()
            var packageName1 = context.getBasePackageName()
            console.log("context.getBasePackageName()=", packageName1)
        }
    })
    return packageName
}

//对一个jni函数进行demangle
function demangle(name) {
    // demangle("_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi")
    // extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
    var __cxa_demangle = DebugSymbol.fromName("__cxa_demangle").address;
    var func_demangle = new NativeFunction(__cxa_demangle, "pointer", ["pointer", "pointer", "pointer", "pointer"])
    // var str = Memory.allocUtf8String("_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi");
    var str = Memory.allocUtf8String(name);
    var result = func_demangle(new NativePointer(ptr(str)), ptr(0), ptr(0), ptr(0));
    // console.log((result).readCString())
    return result.readCString()
    // console.log(JSON.stringify(Module.enumerateSymbols("libart.so")))
}

//模仿wallbreaker的dumpClass
function LookupClass(classFullName) {
    Java.performNow(function () {
        var tmpClass = Java.use(classFullName)
        var packageName = tmpClass.class.getPackage().getName()
        var field_all = tmpClass.class.getDeclaredFields();
        var Modifier = Java.use("java.lang.reflect.Modifier");
        var user_log_list = []
        var classObj = {
            "static_fileds": [],
            "ins_fields": [],
            "contructor_methods": [],
            "static_methods": [],
            "methods": []
        }
        for (var i = 0; i < field_all.length; i++) {
            var field = field_all[i]
            var fieldType = field.getType().getName();
            var fieldName = field.getName();
            var isStatic = Modifier.isStatic(field.getModifiers())
            if (isStatic) {
                var fieldValue = tmpClass[fieldName].value;
                classObj["static_fileds"].push({
                    "key": fieldType + " " + fieldName,
                    // "key": field,
                    "value": fieldValue
                })
            } else {
                classObj["ins_fields"].push({
                    "key": fieldType + " " + fieldName,
                    "value": null
                })
            }
        }
        var method_init_all = tmpClass.class.getDeclaredConstructors();
        for (var i = 0; i < method_init_all.length; i++) {
            var method_init = method_init_all[i]
            var method_init_str = method_init.toString().split("throws")[0].trim()
            // var method_init_ReturnType = method_init.getReturnType()
            var method_init_ParameterTypes = method_init.getParameterTypes()
            var method_init_ParameterTypesStr = getParameterTypesToString(method_init_ParameterTypes)
            var method_init_str = "$init(" + method_init_ParameterTypesStr + ")"
            // var methodName = method.getName()
            classObj["contructor_methods"].push(method_init_str)
        }
        var method_all = tmpClass.class.getDeclaredMethods();
        for (var i = 0; i < method_all.length; i++) {
            var method = method_all[i]
            var methodStr = method.toString().split("throws")[0].trim()
            var methodReturnType = method.getReturnType().getName()
            var methodName = method.getName()
            var methodParameterTypes = method.getParameterTypes()
            var method_ParameterTypesStr = getParameterTypesToString(methodParameterTypes)
            var method_str = methodReturnType + " " + methodName + " (" + method_ParameterTypesStr + ")"
            var isStatic = Modifier.isStatic(method.getModifiers())
            if (isStatic) {
                // classObj["static_methods"].push("(" + methodReturnType + ") " + methodName+" ("+methodParameterTypes)
                classObj["static_methods"].push(method_str)
            } else {
                // console.log("ins value=",fieldName,ins[fieldName].value)
                classObj["methods"].push(method_str)
            }
        }
        //开始打印classObj
        var user_log_list = []
        var tab = new Array(8).join(" ")
        user_log_list.push("package " + packageName + ";")
        console.log(classFullName.slice(classFullName.indexOf(packageName)))
        user_log_list.push("class " + classFullName.slice(packageName.length + 1) + " {")
        user_log_list.push("")
        user_log_list.push(tab + "/* static fields */")
        var static_fileds = classObj["static_fileds"]
        for (var i = 0; i < static_fileds.length; i++) {
            var tmpField = static_fileds[i]
            var tmpFieldName = tmpField["key"]
            var tmpFieldValue = tmpField["value"]
            user_log_list.push(tab + tmpFieldName + " => " + tmpFieldValue)
        }
        user_log_list.push("")
        user_log_list.push(tab + "/* instance fields */")
        var ins_fields = classObj["ins_fields"]
        for (var i = 0; i < ins_fields.length; i++) {
            var tmpField = ins_fields[i]
            var tmpFieldName = tmpField["key"]
            var tmpFieldValue = tmpField["value"]
            user_log_list.push(tab + tmpFieldName + " => " + tmpFieldValue)
        }
        user_log_list.push("")
        user_log_list.push(tab + "/* constructor methods */")
        var contructor_methods = classObj["contructor_methods"]
        for (var i = 0; i < contructor_methods.length; i++) {
            var contructor_method = contructor_methods[i]
            user_log_list.push(tab + contructor_method)
        }
        user_log_list.push("")
        user_log_list.push(tab + "/* static methods */")
        var static_methods = classObj["static_methods"]
        for (var i = 0; i < static_methods.length; i++) {
            var static_method = static_methods[i]
            user_log_list.push(tab + static_method)
        }
        user_log_list.push("")
        user_log_list.push(tab + "/* methods */")
        var methods = classObj["methods"]
        for (var i = 0; i < methods.length; i++) {
            var method = methods[i]
            user_log_list.push(tab + method)
        }
        user_log_list.push("}")
        print_java_log(user_log_list, classFullName)
    })
}

function getParameterTypesToString(parameterTypes) {
    var result = []
    for (var i = 0; i < parameterTypes.length; i++) {
        var tmpType = parameterTypes[i]
        var typeName = tmpType.getName()
        result.push(typeName)
    }
    return result.join(", ")
}

function get_self_process_name() {
    var openPtr = Module.getExportByName('libc.so', 'open');
    var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
    var readPtr = Module.getExportByName("libc.so", "read");
    var read = new NativeFunction(readPtr, "int", ["int", "pointer", "int"]);
    var closePtr = Module.getExportByName('libc.so', 'close');
    var close = new NativeFunction(closePtr, 'int', ['int']);
    var path = Memory.allocUtf8String("/proc/self/cmdline");
    var fd = open(path, 0);
    if (fd != -1) {
        var buffer = Memory.alloc(0x1000);
        var result = read(fd, buffer, 0x1000);
        close(fd);
        result = ptr(buffer).readCString();
        return result;
    }
    return "-1";
}

function mkdir(path) {
    var mkdirPtr = Module.getExportByName('libc.so', 'mkdir');
    var mkdir = new NativeFunction(mkdirPtr, 'int', ['pointer', 'int']);
    var opendirPtr = Module.getExportByName('libc.so', 'opendir');
    var opendir = new NativeFunction(opendirPtr, 'pointer', ['pointer']);
    var closedirPtr = Module.getExportByName('libc.so', 'closedir');
    var closedir = new NativeFunction(closedirPtr, 'int', ['pointer']);
    var cPath = Memory.allocUtf8String(path);
    var dir = opendir(cPath);
    if (dir != 0) {
        closedir(dir);
        return 0;
    }
    mkdir(cPath, 755);
    chmod(path);
}

function chmod(path) {
    var chmodPtr = Module.getExportByName('libc.so', 'chmod');
    var chmod = new NativeFunction(chmodPtr, 'int', ['pointer', 'int']);
    var cPath = Memory.allocUtf8String(path);
    chmod(cPath, 755);
}

function save_permission() {
    var save_permission = false
    try {
        var dex_path = "/sdcard/lingzhiyi_test.txt";
        // var dex_path = "/data/data/"+getPackageName()+"/lingzhiyi_test.txt";
        var fd = new File(dex_path, "wb");
        fd.write("hello");
        fd.flush();
        fd.close()
        save_permission = true;
    } catch (e) {
        // console.log(e)
    }
    return save_permission
}

function dexdump_DexCache() {
    Java.performNow(function () {
        var dex_count = 1;
        Java.choose("java.lang.DexCache", {
            onMatch: function (ins) {
                var name = "" // 不过滤
                // var name = get_self_process_name() // 开启,只在包含当前包名的路劲过滤
                if (ins.location.value.indexOf(name) != -1) {
                    var save_name = ins.location.value.replaceAll("/", "_").replaceAll(".", "_").replaceAll(":", "_").replaceAll("!", "_").replaceAll("-", "_")
                    var dex_file = ins.dexFile.value
                    var base = ptr(dex_file).add(Process.pointerSize).readPointer();
                    var size = ptr(dex_file).add(Process.pointerSize + Process.pointerSize).readUInt();
                    var magic = ptr(base).readCString();
                    if (magic.indexOf("dex") == 0) {
                        var process_name = get_self_process_name();
                        if (process_name != "-1") {
                            if (has_save_permission) {
                                var dex_dir_path = "/sdcard/" + "dumpdex_" + process_name;
                                mkdir(dex_dir_path);
                            }
                            else {
                                var dex_dir_path = "/data/data/" + process_name; // no save permission
                            }
                            var dex_path = dex_dir_path + "/dumpdex_" + save_name + "_DexCache.dex";
                            var fd = new File(dex_path, "wb");
                            if (fd && fd != null) {
                                dex_count++;
                                var dex_buffer = ptr(base).readByteArray(size);
                                fd.write(dex_buffer);
                                fd.flush();
                                fd.close();
                                console.log("[dump dex]:", dex_path);
                            }
                        }
                    }
                }
            },
            onComplete: function () { }
        })
    })
}

function dexdump_Frida() {
    Process.enumerateRanges("r--").forEach(range => {
        // {"base":"0x70e67000","size":2707456,"protection":"r-x","file":{"path":"/system/framework/arm64/boot.oat","offset":757760,"size":0}}
        if (range.file && range.file.path && (range.file.path.startsWith("/system/") || range.file.path.startsWith("/data/dalvik-cache") || range.file.path.startsWith("/dev/kg"))) {
            return
        } else {
            // console.log(JSON.stringify(range))
        }
        try {
            Memory.scanSync(range.base, range.size, "64 65 78 0a 30 ?? ?? 00").forEach(function (match) {
                var base = match.address
                var size = base.add(0x20).readUInt()
                var buffer = ptr(base).readByteArray(size)
                var path = range.file.path.replaceAll("/", "_").replaceAll("-", "_").replaceAll("=", "_").replaceAll(".", "_")
                if (has_save_permission) {
                    var savepath = "/sdcard/" + "dumpdex_" + get_self_process_name();
                    mkdir(savepath);
                }
                else {
                    var savepath = "/data/data/" + get_self_process_name(); // no save permission
                }
                var dex_file_name = savepath + "/dumpdex_" + path + "_frida.dex"
                var file = new File(dex_file_name, "wb")
                file.write(buffer)
                file.flush()
                file.close()
                console.log("dump=>" + dex_file_name)
            })
        }
        catch (e) {
            console.log(e)
        }
    })
    console.log("dumpdex_frida finished~")
}

function readStdString(str) {
    const isTiny = (str.readU8() & 1) == 0;
    if (isTiny) {
        return str.add(1).readUtf8String();
    }
    return str.add(2 * Process.pointerSize).readPointer().readUtf8String();
}

function callprettymethod_x86(artmethodptr) {
    var ArtMethodPrettyMethodaddr = Module.findExportByName("libart.so", "_ZN3art12PrettyMethodEPNS_9ArtMethodEb");
    var ArtMethodPrettyMethodfunc = new NativeFunction(ArtMethodPrettyMethodaddr, "pointer", ["pointer", "pointer", "bool"]);
    var strptr = Memory.alloc(64);
    var ArtMethodName = null;
    if (strptr != null) {
        ArtMethodPrettyMethodfunc(ptr(strptr), ptr(artmethodptr), 1);
        ArtMethodName = readStdString(strptr);
        return ArtMethodName;
    }
    return null;
}

function callPrettyMethod_new(ArtMethodptr) {
    var PrettyMethodfunc = new NativeFunction(PrettyMethod_addr, ["pointer", "pointer", "pointer"], ["pointer", "int"]);
    var result = PrettyMethodfunc(ArtMethodptr, 1);
    var stdstring = Memory.alloc(3 * Process.pointerSize);
    ptr(stdstring).writePointer(result[0]);
    ptr(stdstring).add(1 * Process.pointerSize).writePointer(result[1]);
    ptr(stdstring).add(2 * Process.pointerSize).writePointer(result[2]);
    var result = readStdString(stdstring)
    // console.log("ArtMethodptr="+ArtMethodptr+"----result="+result)
    return result
}

// 同时安卓7的artMethod没有PrettyMethod
function callPrettyMethod_arm32(artmethodptr) {
    var ArtMethodPrettyMethodfunc = new NativeFunction(PrettyMethod_addr, "pointer", ["pointer", "pointer", "pointer"]);
    var strptr = Memory.alloc(256);
    var ArtMethodName = null;
    if (strptr != null) {
        ArtMethodPrettyMethodfunc(ptr(strptr), ptr(artmethodptr), ptr(1));
        ArtMethodName = readStdString(strptr);
        return ArtMethodName;
    }
    return null;
}
var method_name_all = []
// var method_name_all_set  = Array.from(new Set(method_name_all)) // 通过该方法去重获取都调用了哪些方法
function ArtMethodInvoke_filter(methodname) {
    if (methodname == null) {
        return methodname
    }
    method_name_all.push(methodname)
    var method_filter_all = ["android.view", "java.lang.ref", "android.content.res.Configuration", "android.os.BinderProxy", "java.lang.String.intern", "java.util.Locale", "android.os.Binder", "android.graphics", "android.system", "java.lang.ClassNotFoundException", "java.lang.NoSuchFieldError", "android.widget", "dalvik.system.VMStack", "java.lang.System", "java.lang.StringBuilder.append", "java.lang.Object.<init>", "java.net.InetAddress", "android.hardware"]

    var filter = false
    for (var i = 0; i < method_filter_all.length; i++) {
        if (methodname.indexOf(method_filter_all[i]) != -1) {
            filter = true
            break
        }
    }
    // filter = false
    if (!filter) {
        // console.log("enter InvokeWithArgArray callded methodname->" + methodname)
        return "enter InvokeWithArgArray callded methodname->" + methodname
    }
    return null;
}

function hook_ArtMethod_Invoke() {
    if (Process.arch == "ia32") {
        ArtMethodInvoke_addr = DebugSymbol.fromName("_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc").address;
    }
    // void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, const char* shorty)
    Interceptor.attach(ArtMethodInvoke_addr, {
        onEnter: function (args) {
            this.user_log_list = []
            this.called_method = args[0]
            this.vregs_ = args[2]
            this.result = args[4]
            var keep = 1
            var filter_methodname = "SharedPreferences"
            // this.user_log_list.push("onEnter ArtMethodInvoke [this.method_args_size]=" + this.method_args_size)
            if (Process.arch == "ia32") {
                // 模拟器安卓7.0
                this.methodname = callprettymethod_x86((this.called_method));
            } else {
                this.methodname = callPrettyMethod_new((this.called_method));
            }
            if (is_print_native_stackTrace) {
                this.user_log_list.push(('called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'))
            }
            this.flag = (keep && (this.methodname.indexOf(filter_methodname) != -1)) || (!keep)
            // try {
            if (this.flag) {
                this.user_log_list.push("current_called->" + this.methodname)
                // print_native_log(this.user_log_list,"ArtInterpreterToInterpreterBridge")
                // console.log("enter ArtInterpreterToInterpreterBridge=>access_flags_value:"+access_flags_value_+"---called:"+prettymethod_name+"---number_of_vregs_:"+number_of_vregs_.readUInt())
            }
            // } catch (e) {
            //     console.log("ArtMethodInvoke_addr error=======>", e, called_method)
            // }

            // 在此处进行休眠附加调试
            if (this.methodname.indexOf("._ts_getRequestHeader") != -1) {
                console.log("正在调用_ts_getRequestHeader函数,休眠60s 尽快ida或者gdb去附加调试")
                // sleep(60)
            }
        }, onLeave: function (retval) {
            if (is_print_art_param) {
                if (this.flag) {
                    var access_flags = ptr(this.called_method).add(0x4)
                    var access_flags_value = access_flags.readU16()
                    var access_flags_value_ = get_access_flag(access_flags_value)

                    if (access_flags_value_ != access_flags_value) {
                        var args_list_str = this.methodname.split("(")[1].split(")")[0]
                        if (args_list_str.length == 0) {
                            var args_len = 0
                        } else {
                            var args_list_name = args_list_str.split(",")
                            var args_len = args_list_name.length
                        }
                        var origin_len = args_len
                        var start_index = 0
                        var is_not_static = 0
                        if (access_flags_value_.indexOf("static") != -1) {
                            // 说明是静态方法
                            this.user_log_list.push("is static")
                        } else {
                            // 非静态,是实例方法,第一个参数
                            start_index += 1
                            is_not_static = 1
                            args_len += 1
                            this.user_log_list.push("is instance")
                        }
                        var offset = 0
                        if (origin_len == 0x0) {
                            // 说明参数个数为0
                            // this.user_log_list.push("参数个数为0")
                        } else {
                            // this.user_log_list.push("参数个数为"+args_len+"   origin_len="+origin_len)
                            for (; start_index < args_len; start_index++) {
                                var arg_name = args_list_name[start_index - is_not_static]
                                var address = ptr(this.vregs_).add(4 * start_index + offset)
                                var print_name = get_native_value(address, arg_name, start_index - is_not_static)
                                this.user_log_list.push(print_name)
                                if (arg_name.indexOf("long") != -1) {
                                    offset += 4
                                }
                            }
                        }
                    } else {
                        //todo
                    }
                    this.user_log_list.push("called_access_flags_value:" + access_flags_value_.toString(16))
                    this.user_log_list.push("called:" + this.methodname)
                }
            }

            if (this.flag) {
                if (is_print_art_retval) {
                    this.return_type = this.methodname.split(" ")[0]
                    if (this.return_type != "void") {
                        var print_name = get_native_value(this.result, this.return_type, "return")
                        if (print_name != null) {
                            this.user_log_list.push(print_name)
                        }
                    }
                }
                print_native_log(this.user_log_list, "onLeave [libart.so => ArtMethodInvoke]=" + ArtMethodInvoke_addr)
            }
        }
    })
}

function hook_ArtMethod_RegisterNative() {
    // var ArtMethodRegisterNative_addr = Module.findExportByName("libart.so", "_ZN3art9ArtMethod14RegisterNativeEPKvb");
    // console.log("ArtMethodRegisterNative_addr=",ArtMethodRegisterNative_addr)
    Interceptor.attach(ArtMethodRegisterNative_addr, {
        onEnter: function (args) {
            this.artmethod = args[0];
            var methodname = callPrettyMethod_new(ptr(this.artmethod));
            if (methodname.indexOf("MainActivity.onCreate") != -1) {
                console.log("find MainActivity.onCreate ready to sleep 60s")
                // sleep(60)
            }
            // var methodname = (ptr(this.artmethod));
            var address = args[1];
            this.dex_method_index_ = ptr(this.artmethod).add(12).readU32();
            var current_module = Process.getModuleByAddress(address)
            var modulename = current_module.name
            var base = current_module.base
            var offset = address.sub(base)
            console.log("go into ArtMethodRegisterNative---" + "artmethodptr:" + ptr(this.artmethod) + "---methodidx:" + this.dex_method_index_ + "--addr:" + address + "----name:" + methodname + "---modulename:" + modulename + "---offset:" + offset);
        }, onLeave: function (retval) {
        }
    })
}

function is_java_func_static(java_func_name) {
    if (java_func_name.indexOf("<") != -1) {
        return false
    }
    var result = false
    Java.performNow(function () {
        var java_func_name_split = java_func_name.split(".")
        var classname_array = []
        var java_func_short_name = java_func_name_split[java_func_name_split.length - 1]
        for (var i = 0; i < java_func_name_split.length - 1; i++) {
            classname_array.push(java_func_name_split[i])
        }
        var classname = classname_array.join(".")
        var tmpClass = Java.use(classname)
        var Modifier = Java.use("java.lang.reflect.Modifier");
        var method_all = tmpClass.class.getDeclaredMethods();
        for (var i = 0; i < method_all.length; i++) {
            var method = method_all[i]
            var methodName = method.getName()
            if (methodName == java_func_short_name) {
                var isStatic = Modifier.isStatic(method.getModifiers())
                result = isStatic
            }
        }
    })
    return result
}

function can_hexdump(addr) {
    var range = Process.findRangeByAddress(addr)
    if (range != null) {
        return hexdump(addr) + "\r\n"
    } else {
        return addr + "\r\n"
    }
}

/*
so加载后会执行init,initarray以及JNI_OnLoad,动态注册一般会放在JNI_OnLoad中
*/
function hook_JNI_OnLoad() {
    // jint JNI_OnLoad(JavaVM *vm, void *reserved)
    // var JNI_Onload_addr = DebugSymbol.fromName("JNI_OnLoad").address;
    var JNI_Onload_addr = Module.findExportByName("libmedia_jni.so", "JNI_OnLoad");
    // var JNI_Onload_addr = Module.findExportByName(null,"JNI_OnLoad");
    console.log("JNI_Onload_addr=", JNI_Onload_addr)
    Interceptor.attach(JNI_Onload_addr, {
        onEnter: function (args) {
            // console.log("enter JNI_Onload_addr")
        },
        onLeave: function (retval) {
            // console.log("leave JNI_Onload_addr")
        }
    })
}
/*
对动态加载的dex,可以在这里进行hook,或者是更底层
*/
function hook_loadLibrary0() {
    Java.performNow(function () {
        Java.use("java.lang.Runtime").loadLibrary0.implementation = function (classloader, sopath) {
            // hook_InvokeWithArgArray_x86()
            var result = this.loadLibrary0(classloader, sopath);
            var user_log_list = []
            user_log_list.push("[classloader]=" + classloader)
            user_log_list.push("[sopath]=" + sopath)
            print_log(user_log_list, "java.lang.Runtime.loadLibrary0")
            // try{
            //     if(classloader.findClass("com.taobao.wireless.security.adapter.JNICLibrary")!=-1){
            //         Java.classFactory.loader = classloader
            //         // hookOneClass("com.taobao.wireless.security.adapter.JNICLibrary")
            //         hookOneMethod("com.taobao.wireless.security.adapter.JNICLibrary.doCommandNative")
            //     }
            // }catch(e){
            // }
            return result;
        }
    })
}

function get_access_flag(i) {
    // var j = parseInt(i)
    var result = i
    var dict = {
        0x1: "public",
        0x2: "private",
        0x4: "protected",
        0x8: "static",
        0x9: "public static",
        0xa: "private static",
        0x10: "final",
        0x11: "public final",
        0x12: "private final",
        0x19: "public final static",
        0x1a: "private final static",
        0x101: "public native",
        0x102: "private native",
        0x109: "public static native",
        0x10a: "private static native",
        0x111: "public final native",
        0x112: "private final native",
        0x119: "public final static native",// 0x1 0x10 0x8 0x100
        0x11a: "private final static native",// 0x2 0x10 0x8 0x100
        0x1008: "Synthetic static ",// 0x8 0x1000
    }
    if (dict[i] != undefined) {
        var result = dict[i]
    }
    return result
}

function hook_ArtInterpreterToInterpreterBridge() {
    // var ArtInterpreterToInterpreterBridge_addr = Module.findExportByName("libart.so", "_ZN3art11interpreter33ArtInterpreterToInterpreterBridgeEPNS_6ThreadEPKNS_7DexFile8CodeItemEPNS_11ShadowFrameEPNS_6JValueE")
    Interceptor.attach(ArtInterpreterToInterpreterBridge_addr, {
        onEnter: function (args) {
            // try {
            this.keep = 1
            var filter_name = "android.app.SharedPreferencesImpl.getString"
            this.user_log_list = []
            var codeitem = args[1]
            // this.user_log_list.push(hexdump(codeitem)) 
            this.callee_frame = args[2]
            this.JValue_result = args[3]
            if (is_print_native_stackTrace) {
                // this.user_log_list.push(('called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'))
            }
            var callee_frame = this.callee_frame
            var called_method = ptr(callee_frame).add(Process.pointerSize).readPointer();
            var prettymethod_name = callPrettyMethod_new(called_method)
            // console.log("ArtInterpreterToInterpreterBridge->"+prettymethod_name)
            // return 
            this.prettymethod_name = prettymethod_name
            this.flag = (this.keep && prettymethod_name.indexOf(filter_name) != -1) || (!this.keep)
            this.return_type = prettymethod_name.split(" ")[0]
            if (this.flag) {
                this.user_log_list.push("current_called->" + prettymethod_name)
            }
            if (is_print_art_param) {
                if (this.flag) {
                    var access_flags = ptr(called_method).add(0x4)
                    var access_flags_value = access_flags.readU16()
                    var access_flags_value_ = get_access_flag(access_flags_value)
                    // console.log(called_method,hexdump(callee_frame),"\r\n",hexdump(called_method))
                    var number_of_vregs_ = ptr(callee_frame).add(Process.pointerSize * 6);
                    var vregs_ = ptr(callee_frame).add(Process.pointerSize * 6).add(12)
                    if (access_flags_value_ != access_flags_value) {
                        var args_list_str = prettymethod_name.split("(")[1].split(")")[0]
                        if (args_list_str.length == 0) {
                            var args_len = 0
                        } else {
                            var args_list_name = args_list_str.split(",")
                            var args_len = args_list_name.length
                        }
                        var origin_len = args_len
                        var start_index = 0
                        var is_static = 0
                        if (access_flags_value_.indexOf("static") != -1) {
                            // 说明是静态方法
                            this.user_log_list.push("is static~~~")
                        } else {
                            // 非静态,是实例方法,第一个参数
                            start_index += 1
                            is_static = 1
                            args_len += 1
                            this.user_log_list.push("is instance~~~")
                        }
                        var offset = 0
                        if (origin_len == 0x0) {
                            // 说明参数个数为0
                            // this.user_log_list.push("参数个数为0")
                        } else {
                            // this.user_log_list.push("参数个数为"+args_len+"   origin_len="+origin_len)
                            for (; start_index < args_len; start_index++) {
                                var arg_name = args_list_name[start_index - is_static]
                                var address = ptr(vregs_).add(4 * start_index + offset)
                                var print_name = get_native_value(address, arg_name, start_index - is_static)
                                this.user_log_list.push(print_name)
                                if (arg_name.indexOf("long") != -1) {
                                    offset += 4
                                }
                            }
                        }
                    } else {
                        //todo
                    }
                    this.user_log_list.push("called_access_flags_value:" + access_flags_value_.toString(16))
                    this.user_log_list.push("called:" + prettymethod_name)
                    // print_native_log(this.user_log_list, "ArtInterpreterToInterpreterBridge")
                    // console.log("enter ArtInterpreterToInterpreterBridge=>access_flags_value:"+access_flags_value_+"---called:"+prettymethod_name+"---number_of_vregs_:"+number_of_vregs_.readUInt())
                }
            }

            // } catch (e) {
            //     console.log("ArtInterpreterToInterpreterBridge error=======>", e, called_method)
            // }
        },
        onLeave: function (retval) {
            if (this.flag) {
                if (is_print_art_retval) {
                    if (this.return_type != "void") {
                        var print_name = get_native_value(this.JValue_result, this.return_type, "return")
                        if (print_name != null) {
                            this.user_log_list.push(print_name)
                        }
                    }
                    // if (this.JValue_result != 0x0) {
                    //     this.user_log_list.push("this.JValue_result=")
                    //     this.user_log_list.push(hexdump(this.JValue_result))
                    //     // console.log("this.JValue_result=",hexdump(this.JValue_result))
                    // }
                }
                print_native_log(this.user_log_list, "ArtInterpreterToInterpreterBridge")
            }

        }
    })

}

function hook_ArtInterpreterToCompiledCodeBridge() {
    Interceptor.attach(ArtInterpreterToCompiledCodeBridge_addr, {
        onEnter: function (args) {
            // try {
            var keep = 1
            var filter_name = "android.app.SharedPreferencesImpl"
            this.caller_method = args[1]
            this.callee_frame = args[2]
            this.JValue_result = args[4]
            this.user_log_list = []
            if (is_print_native_stackTrace) {
                // 崩溃的原因是这个
                // this.user_log_list.push(('called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'))
            }
            var caller_method = this.caller_method // caller_method可能是0x0
            var callee_frame = this.callee_frame
            var called_method = ptr(callee_frame).add(Process.pointerSize).readPointer();
            var prettymethod_name = callPrettyMethod_new(called_method)
            // console.log("ArtInterpreterToCompiledCodeBridge->"+prettymethod_name)
            // return 0

            if (caller_method != 0x0) {
                var prettymethod_name_caller = callPrettyMethod_new(caller_method)
            }
            this.flag = (keep && ((prettymethod_name.indexOf(filter_name) != -1) || (caller_method != 0x0 && prettymethod_name_caller.indexOf(filter_name) != -1))) || (!keep)
            if (this.flag) {
                // java_init()
                // java_hook_wrapper()
                // console.log("args=",args[0],args[1],args[2],args[3],args[4])
                this.user_log_list.push("current_called->" + prettymethod_name)
            }
            this.return_type = prettymethod_name.split(" ")[0]
            if (is_print_art_param) {
                if (this.flag) {
                    if (caller_method != 0x0) {
                        var caller_access_flags = ptr(caller_method).add(0x4)
                        var caller_access_flags_value = caller_access_flags.readU16()
                        var caller_access_flags_value_ = get_access_flag(caller_access_flags_value)
                    }
                    var called_access_flags = ptr(called_method).add(0x4)
                    var called_access_flags_value = called_access_flags.readU16()
                    var called_access_flags_value_ = get_access_flag(called_access_flags_value)
                    var number_of_vregs_ = ptr(callee_frame).add(Process.pointerSize * 6);
                    var vregs_ = ptr(callee_frame).add(Process.pointerSize * 6).add(12)


                    if (called_access_flags_value != called_access_flags_value_) {
                        var args_list_str = prettymethod_name.split("(")[1].split(")")[0]
                        if (args_list_str.length == 0) {
                            var args_len = 0
                        } else {
                            var args_list_name = args_list_str.split(",")
                            var args_len = args_list_name.length
                        }
                        var origin_len = args_len
                        var start_index = 0
                        var is_not_static = 0
                        if (called_access_flags_value_.indexOf("static") != -1) {
                            // 说明是静态方法
                            this.user_log_list.push("is static!!!!")
                        } else {
                            // 非静态,是实例方法,第一个参数
                            start_index += 1
                            is_not_static = 1
                            args_len += 1
                            this.user_log_list.push("is instance!!!!")
                        }
                        var offset = 0
                        if (origin_len == 0x0) {
                            // 说明参数个数为0
                            // this.user_log_list.push("参数个数为0")
                        } else {
                            // this.user_log_list.push("参数个数为"+args_len+"   origin_len="+origin_len)
                            for (; start_index < args_len; start_index++) {
                                var arg_name = args_list_name[start_index - is_not_static]
                                var address = ptr(vregs_).add(4 * start_index + offset)
                                var print_name = get_native_value(address, arg_name, start_index - is_not_static)
                                this.user_log_list.push(print_name)
                                if (arg_name.indexOf("long") != -1) {
                                    offset += 4
                                }
                            }
                        }
                    } else {
                        //todo
                    }
                    if (caller_method != 0x0) {
                        this.user_log_list.push("caller_access_flags_value:" + caller_access_flags_value_.toString(16))
                        this.user_log_list.push("caller:" + prettymethod_name_caller)
                    } else {
                        this.user_log_list.push("caller:" + "0x0")
                    }
                    this.user_log_list.push("called_access_flags_value:" + called_access_flags_value_.toString(16))
                    this.user_log_list.push("called:" + prettymethod_name)
                    // print_native_log(this.user_log_list, "ArtInterpreterToCompiledCodeBridge")
                }
            }
            // } catch (e) {
            //     console.log("ArtInterpreterToCompiledCodeBridge error=======>", e, caller_method, called_method)
            // }
        },
        onLeave: function (retval) {
            if (this.flag) {
                if (is_print_art_retval) {
                    // if(this.return_type!="void" && this.JValue_result != 0x0){
                    // console.log(this.return_type)
                    // console.log(this.JValue_result)
                    if (this.return_type != "void") {
                        var print_name = get_native_value(this.JValue_result, this.return_type, "return")
                        if (print_name != null) {
                            this.user_log_list.push(print_name)
                        }
                    }

                    //     this.user_log_list.push(print_name)
                    // console.log(print_name)
                    // if (this.JValue_result != 0x0) {
                    //     this.user_log_list.push("this.JValue_result=")
                    //     this.user_log_list.push(hexdump(this.JValue_result))
                    // }
                    // }
                }
                print_native_log(this.user_log_list, "ArtInterpreterToCompiledCodeBridge")
            }
        }
    })
}

function hook_Art_Interpreter_Invoke() {
    // 总共有四种情况的执行方法
    /*
        1. 机器码->机器码
        2. 机器码->解释执行
        3. 解释执行->解释执行
        4. 解释执行->机器码
    */
    // 1. 机器码->机器码
    // extern "C" TwoWordReturn artQuickGenericJniTrampoline(Thread* self, ArtMethod** sp)
    Interceptor.attach(artQuickGenericJniTrampoline_addr, {
        onEnter: function (args) {
            // try {
            this.keep = 0
            var filter_name = "Request"
            this.user_log_list = []
            // this.callee_frame = args[2]
            // this.JValue_result = args[3]
            if (is_print_native_stackTrace) {
                this.user_log_list.push(('called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'))
            }
            // var callee_frame = this.callee_frame
            var called_method = args[1].readPointer()
            var prettymethod_name = callPrettyMethod_new(called_method)
            // console.log("ArtInterpreterToInterpreterBridge->"+prettymethod_name)
            // return 
            this.prettymethod_name = prettymethod_name
            this.flag = (this.keep && prettymethod_name.indexOf(filter_name) != -1) || (!this.keep)
            this.return_type = prettymethod_name.split(" ")[0]
            if (this.flag) {
                this.user_log_list.push("current_called->" + prettymethod_name)
            }
            if (is_print_art_param) {
                return
                if (this.flag) {
                    var access_flags = ptr(called_method).add(0x4)
                    var access_flags_value = access_flags.readU16()
                    var access_flags_value_ = get_access_flag(access_flags_value)
                    // console.log(called_method,hexdump(callee_frame),"\r\n",hexdump(called_method))
                    var number_of_vregs_ = ptr(callee_frame).add(Process.pointerSize * 6);
                    var vregs_ = ptr(callee_frame).add(Process.pointerSize * 6).add(12)
                    if (access_flags_value_ != access_flags_value) {
                        var args_list_str = prettymethod_name.split("(")[1].split(")")[0]
                        if (args_list_str.length == 0) {
                            var args_len = 0
                        } else {
                            var args_list_name = args_list_str.split(",")
                            var args_len = args_list_name.length
                        }
                        var origin_len = args_len
                        var start_index = 0
                        var is_static = 0
                        if (access_flags_value_.indexOf("static") != -1) {
                            // 说明是静态方法
                            this.user_log_list.push("is static~~~")
                        } else {
                            // 非静态,是实例方法,第一个参数
                            start_index += 1
                            is_static = 1
                            args_len += 1
                            this.user_log_list.push("is instance~~~")
                        }
                        var offset = 0
                        if (origin_len == 0x0) {
                            // 说明参数个数为0
                            // this.user_log_list.push("参数个数为0")
                        } else {
                            // this.user_log_list.push("参数个数为"+args_len+"   origin_len="+origin_len)
                            for (; start_index < args_len; start_index++) {
                                var arg_name = args_list_name[start_index - is_static]
                                var address = ptr(vregs_).add(4 * start_index + offset)
                                var print_name = get_native_value(address, arg_name, start_index - is_static)
                                this.user_log_list.push(print_name)
                                if (arg_name.indexOf("long") != -1) {
                                    offset += 4
                                }
                            }
                        }
                    } else {
                        //todo
                    }
                    this.user_log_list.push("called_access_flags_value:" + access_flags_value_.toString(16))
                    this.user_log_list.push("called:" + prettymethod_name)
                    // print_native_log(this.user_log_list, "ArtInterpreterToInterpreterBridge")
                    // console.log("enter ArtInterpreterToInterpreterBridge=>access_flags_value:"+access_flags_value_+"---called:"+prettymethod_name+"---number_of_vregs_:"+number_of_vregs_.readUInt())
                }
            }

            // } catch (e) {
            //     console.log("ArtInterpreterToInterpreterBridge error=======>", e, called_method)
            // }
        },
        onLeave: function (retval) {
            if (this.flag) {
                print_native_log(this.user_log_list, "artQuickGenericJniTrampoline")
            }

        }
    })

    // 2. 机器码->解释执行
    // extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, ArtMethod** sp)
    Interceptor.attach(artQuickToInterpreterBridge_addr, {
        onEnter: function (args) {
            // try {
            var keep = 0
            var filter_name = "get2"
            this.caller_method = args[2].readPointer()
            // this.callee_frame = args[2]
            // this.JValue_result = args[4]
            this.user_log_list = []
            if (is_print_native_stackTrace) {
                // 崩溃的原因是这个
                this.user_log_list.push(('called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'))
            }
            var caller_method = this.caller_method // caller_method可能是0x0
            // var callee_frame = this.callee_frame
            var called_method = args[0]
            var prettymethod_name = callPrettyMethod_new(called_method)
            // console.log("ArtInterpreterToCompiledCodeBridge->"+prettymethod_name)
            // return 0

            if (caller_method != 0x0) {
                var prettymethod_name_caller = callPrettyMethod_new(caller_method)
            }
            this.flag = (keep && ((prettymethod_name.indexOf(filter_name) != -1) || (caller_method != 0x0 && prettymethod_name_caller.indexOf(filter_name) != -1))) || (!keep)
            if (this.flag) {
                // console.log("args=",args[0],args[1],args[2],args[3],args[4])
                this.user_log_list.push("current_called->" + prettymethod_name)
            }
            this.return_type = prettymethod_name.split(" ")[0]
            if (is_print_art_param) {
                if (this.flag) {
                    return
                    if (caller_method != 0x0) {
                        var caller_access_flags = ptr(caller_method).add(0x4)
                        var caller_access_flags_value = caller_access_flags.readU16()
                        var caller_access_flags_value_ = get_access_flag(caller_access_flags_value)
                    }
                    var called_access_flags = ptr(called_method).add(0x4)
                    var called_access_flags_value = called_access_flags.readU16()
                    var called_access_flags_value_ = get_access_flag(called_access_flags_value)
                    var number_of_vregs_ = ptr(callee_frame).add(Process.pointerSize * 6);
                    var vregs_ = ptr(callee_frame).add(Process.pointerSize * 6).add(12)


                    if (called_access_flags_value != called_access_flags_value_) {
                        var args_list_str = prettymethod_name.split("(")[1].split(")")[0]
                        if (args_list_str.length == 0) {
                            var args_len = 0
                        } else {
                            var args_list_name = args_list_str.split(",")
                            var args_len = args_list_name.length
                        }
                        var origin_len = args_len

                        var start_index = 0
                        var is_not_static = 0
                        if (called_access_flags_value_.indexOf("static") != -1) {
                            // 说明是静态方法
                            this.user_log_list.push("is static!!!!")
                        } else {
                            // 非静态,是实例方法,第一个参数
                            start_index += 1
                            is_not_static = 1
                            args_len += 1
                            this.user_log_list.push("is instance!!!!")
                        }
                        var offset = 0
                        if (origin_len == 0x0) {
                            // 说明参数个数为0
                            // this.user_log_list.push("参数个数为0")
                        } else {
                            // this.user_log_list.push("参数个数为"+args_len+"   origin_len="+origin_len)
                            for (; start_index < args_len; start_index++) {
                                var arg_name = args_list_name[start_index - is_not_static]
                                var address = ptr(vregs_).add(4 * start_index + offset)
                                var print_name = get_native_value(address, arg_name, start_index - is_not_static)
                                this.user_log_list.push(print_name)
                                if (arg_name.indexOf("long") != -1) {
                                    offset += 4
                                }
                            }
                        }
                    } else {
                        //todo
                    }
                    if (caller_method != 0x0) {
                        this.user_log_list.push("caller_access_flags_value:" + caller_access_flags_value_.toString(16))
                        this.user_log_list.push("caller:" + prettymethod_name_caller)
                    } else {
                        this.user_log_list.push("caller:" + "0x0")
                    }
                    this.user_log_list.push("called_access_flags_value:" + called_access_flags_value_.toString(16))
                    this.user_log_list.push("called:" + prettymethod_name)
                    // print_native_log(this.user_log_list, "ArtInterpreterToCompiledCodeBridge")
                }
            }
            // } catch (e) {
            //     console.log("ArtInterpreterToCompiledCodeBridge error=======>", e, caller_method, called_method)
            // }
        },
        onLeave: function (retval) {
            if (this.flag) {
                print_native_log(this.user_log_list, "artQuickToInterpreterBridge")
            }
        }
    })

    // return 
    // 3. 解释执行->解释执行
    Interceptor.attach(ArtInterpreterToInterpreterBridge_addr, {
        onEnter: function (args) {
            // try {
            this.keep = 0
            var filter_name = "Request"
            this.user_log_list = []
            this.callee_frame = args[2]
            this.JValue_result = args[3]
            if (is_print_native_stackTrace) {
                this.user_log_list.push(('called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'))
            }
            var callee_frame = this.callee_frame
            var called_method = ptr(callee_frame).add(Process.pointerSize).readPointer();
            var prettymethod_name = callPrettyMethod_new(called_method)
            // console.log("ArtInterpreterToInterpreterBridge->"+prettymethod_name)
            // return 
            this.prettymethod_name = prettymethod_name
            this.flag = (this.keep && prettymethod_name.indexOf(filter_name) != -1) || (!this.keep)
            this.return_type = prettymethod_name.split(" ")[0]
            if (this.flag) {
                this.user_log_list.push("current_called->" + prettymethod_name)
            }
            if (is_print_art_param) {
                if (this.flag) {
                    var access_flags = ptr(called_method).add(0x4)
                    var access_flags_value = access_flags.readU16()
                    var access_flags_value_ = get_access_flag(access_flags_value)
                    // console.log(called_method,hexdump(callee_frame),"\r\n",hexdump(called_method))
                    var number_of_vregs_ = ptr(callee_frame).add(Process.pointerSize * 6);
                    var vregs_ = ptr(callee_frame).add(Process.pointerSize * 6).add(12)
                    if (access_flags_value_ != access_flags_value) {
                        var args_list_str = prettymethod_name.split("(")[1].split(")")[0]
                        if (args_list_str.length == 0) {
                            var args_len = 0
                        } else {
                            var args_list_name = args_list_str.split(",")
                            var args_len = args_list_name.length
                        }
                        var origin_len = args_len
                        var start_index = 0
                        var is_static = 0
                        if (access_flags_value_.indexOf("static") != -1) {
                            // 说明是静态方法
                            this.user_log_list.push("is static~~~")
                        } else {
                            // 非静态,是实例方法,第一个参数
                            start_index += 1
                            is_static = 1
                            args_len += 1
                            this.user_log_list.push("is instance~~~")
                        }
                        var offset = 0
                        if (origin_len == 0x0) {
                            // 说明参数个数为0
                            // this.user_log_list.push("参数个数为0")
                        } else {
                            // this.user_log_list.push("参数个数为"+args_len+"   origin_len="+origin_len)
                            for (; start_index < args_len; start_index++) {
                                var arg_name = args_list_name[start_index - is_static]
                                var address = ptr(vregs_).add(4 * start_index + offset)
                                var print_name = get_native_value(address, arg_name, start_index - is_static)
                                this.user_log_list.push(print_name)
                                if (arg_name.indexOf("long") != -1) {
                                    offset += 4
                                }
                            }
                        }
                    } else {
                        //todo
                    }
                    this.user_log_list.push("called_access_flags_value:" + access_flags_value_.toString(16))
                    this.user_log_list.push("called:" + prettymethod_name)
                    // print_native_log(this.user_log_list, "ArtInterpreterToInterpreterBridge")
                    // console.log("enter ArtInterpreterToInterpreterBridge=>access_flags_value:"+access_flags_value_+"---called:"+prettymethod_name+"---number_of_vregs_:"+number_of_vregs_.readUInt())
                }
            }

            // } catch (e) {
            //     console.log("ArtInterpreterToInterpreterBridge error=======>", e, called_method)
            // }
        },
        onLeave: function (retval) {
            if (this.flag) {
                if (is_print_art_retval) {
                    if (this.return_type != "void") {
                        var print_name = get_native_value(this.JValue_result, this.return_type, "return")
                        if (print_name != null) {
                            this.user_log_list.push(print_name)
                        }
                    }
                    // if (this.JValue_result != 0x0) {
                    //     this.user_log_list.push("this.JValue_result=")
                    //     this.user_log_list.push(hexdump(this.JValue_result))
                    //     // console.log("this.JValue_result=",hexdump(this.JValue_result))
                    // }
                }
                print_native_log(this.user_log_list, "ArtInterpreterToInterpreterBridge")
            }

        }
    })

    // 4. 解释执行->机器码
    Interceptor.attach(ArtInterpreterToCompiledCodeBridge_addr, {
        onEnter: function (args) {
            // try {
            var keep = 0
            var filter_name = "get2"
            this.caller_method = args[1]
            this.callee_frame = args[2]
            this.JValue_result = args[4]
            this.user_log_list = []
            if (is_print_native_stackTrace) {
                // 崩溃的原因是这个
                this.user_log_list.push(('called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'))
            }
            var caller_method = this.caller_method // caller_method可能是0x0
            var callee_frame = this.callee_frame
            var called_method = ptr(callee_frame).add(Process.pointerSize).readPointer();
            var prettymethod_name = callPrettyMethod_new(called_method)
            // console.log("ArtInterpreterToCompiledCodeBridge->"+prettymethod_name)
            // return 0

            if (caller_method != 0x0) {
                var prettymethod_name_caller = callPrettyMethod_new(caller_method)
            }
            this.flag = (keep && ((prettymethod_name.indexOf(filter_name) != -1) || (caller_method != 0x0 && prettymethod_name_caller.indexOf(filter_name) != -1))) || (!keep)
            if (this.flag) {
                // console.log("args=",args[0],args[1],args[2],args[3],args[4])
                this.user_log_list.push("current_called->" + prettymethod_name)
            }
            this.return_type = prettymethod_name.split(" ")[0]
            if (is_print_art_param) {
                if (this.flag) {
                    if (caller_method != 0x0) {
                        var caller_access_flags = ptr(caller_method).add(0x4)
                        var caller_access_flags_value = caller_access_flags.readU16()
                        var caller_access_flags_value_ = get_access_flag(caller_access_flags_value)
                    }
                    var called_access_flags = ptr(called_method).add(0x4)
                    var called_access_flags_value = called_access_flags.readU16()
                    var called_access_flags_value_ = get_access_flag(called_access_flags_value)
                    var number_of_vregs_ = ptr(callee_frame).add(Process.pointerSize * 6);
                    var vregs_ = ptr(callee_frame).add(Process.pointerSize * 6).add(12)


                    if (called_access_flags_value != called_access_flags_value_) {
                        var args_list_str = prettymethod_name.split("(")[1].split(")")[0]
                        if (args_list_str.length == 0) {
                            var args_len = 0
                        } else {
                            var args_list_name = args_list_str.split(",")
                            var args_len = args_list_name.length
                        }
                        var origin_len = args_len

                        var start_index = 0
                        var is_not_static = 0
                        if (called_access_flags_value_.indexOf("static") != -1) {
                            // 说明是静态方法
                            this.user_log_list.push("is static!!!!")
                        } else {
                            // 非静态,是实例方法,第一个参数
                            start_index += 1
                            is_not_static = 1
                            args_len += 1
                            this.user_log_list.push("is instance!!!!")
                        }
                        var offset = 0
                        if (origin_len == 0x0) {
                            // 说明参数个数为0
                            // this.user_log_list.push("参数个数为0")
                        } else {
                            // this.user_log_list.push("参数个数为"+args_len+"   origin_len="+origin_len)
                            for (; start_index < args_len; start_index++) {
                                var arg_name = args_list_name[start_index - is_not_static]
                                var address = ptr(vregs_).add(4 * start_index + offset)
                                var print_name = get_native_value(address, arg_name, start_index - is_not_static)
                                this.user_log_list.push(print_name)
                                if (arg_name.indexOf("long") != -1) {
                                    offset += 4
                                }
                            }
                        }
                    } else {
                        //todo
                    }
                    if (caller_method != 0x0) {
                        this.user_log_list.push("caller_access_flags_value:" + caller_access_flags_value_.toString(16))
                        this.user_log_list.push("caller:" + prettymethod_name_caller)
                    } else {
                        this.user_log_list.push("caller:" + "0x0")
                    }
                    this.user_log_list.push("called_access_flags_value:" + called_access_flags_value_.toString(16))
                    this.user_log_list.push("called:" + prettymethod_name)
                    // print_native_log(this.user_log_list, "ArtInterpreterToCompiledCodeBridge")
                }
            }
            // } catch (e) {
            //     console.log("ArtInterpreterToCompiledCodeBridge error=======>", e, caller_method, called_method)
            // }
        },
        onLeave: function (retval) {
            if (this.flag) {
                if (is_print_art_retval) {
                    if (this.return_type != "void") {
                        var print_name = get_native_value(this.JValue_result, this.return_type, "return")
                        if (print_name != null) {
                            this.user_log_list.push(print_name)
                        }
                    }
                }
                print_native_log(this.user_log_list, "ArtInterpreterToCompiledCodeBridge")
            }
        }
    })

    // hook_ArtMethod_Invoke()

}

// 初始化java的一些函数和变量
function java_init() {
    Java.performNow(function () {
        StringClass = Java.use("java.lang.String");
        Base64Class = Java.use("android.util.Base64");
        frida_major_version = Frida.version.split(".")[0];
        android_sdk_version = Java.use("android.os.Build$VERSION").SDK_INT.value;
        has_save_permission = save_permission();
        console.log("java_init finished~" + new Array(20).join("-"))
    })
}

// 初始化native层的一些函数和变量
function native_init() {
    var temp_print = 0
    module_libart = Process.findModuleByName("libart.so");
    var module_libart_symbols = module_libart.enumerateSymbols()
    for (var index = 0; index < module_libart_symbols.length; index++) {
        var symbol = module_libart_symbols[index];
        var symbol_name = symbol.name;
        //这个DefineClass的函数签名是Android9的
        //_ZN3art11ClassLinker11DefineClassEPNS_6ThreadEPKcmNS_6HandleINS_6mirror11ClassLoaderEEERKNS_7DexFileERKNS9_8ClassDefE
        if (symbol_name.indexOf("ClassLinker") >= 0 && symbol_name.indexOf("DefineClass") >= 0 && symbol_name.indexOf("Thread") >= 0 && symbol_name.indexOf("DexFile") >= 0) {
            DefineClass_addr = symbol.address;
            if (temp_print) {
                console.log("DefineClass_addr=", DefineClass_addr)
            }
        }
        // if (symbol.name.indexOf("ClassLinker") >= 0 && symbol.name.indexOf("LoadMethod") >= 0 && symbol.name.indexOf("DexFile") >= 0 && symbol.name.indexOf("ClassDataItemIterator") >= 0 && symbol.name.indexOf("ArtMethod") >= 0) {}
        if (symbol.name.indexOf("ClassLinker") >= 0 && symbol.name.indexOf("LoadMethod") >= 0 && symbol.name.indexOf("DexFile") >= 0 && symbol.name.indexOf("ArtMethod") >= 0) {
            LoadMethod_addr = symbol.address;
            if (temp_print) {
                console.log("LoadMethod_addr=", LoadMethod_addr)
            }
        }

        if (symbol.name.indexOf("PrettyMethod") != -1 && symbol.name.indexOf("ArtMethod") != -1 && symbol.name.indexOf("art") != -1) {
            PrettyMethod_addr = symbol.address;
            if (temp_print) {
                console.log("PrettyMethod_addr=", PrettyMethod_addr)
            }
        }
        if (symbol.name.indexOf("RegisterNativeMethod") == -1 && symbol.name.indexOf("ArtMethod") != -1 && symbol.name.indexOf("RegisterNative") != -1) {
            ArtMethodRegisterNative_addr = symbol.address;
            if (temp_print) {
                console.log("ArtMethodRegisterNative_addr=", ArtMethodRegisterNative_addr)
            }
        }
        // _ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc 安卓8.1.0,安卓7.1.2
        if (symbol.name.indexOf("Invoke") != -1 && symbol.name.indexOf("_ZN3art9ArtMethod") != -1 && symbol.name.indexOf("Thread") != -1 && symbol.name.indexOf("JValue") != -1) {
            // console.log("func_name="+symbol.name,"demangle_name="+demangle(symbol.name))
            ArtMethodInvoke_addr = symbol.address;
            if (temp_print) {
                console.log("ArtMethodInvoke_addr=", ArtMethodInvoke_addr)
            }
        }
        // _ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi
        if (symbol.name.indexOf("RegisterNatives") != -1 && symbol.name.indexOf("_ZN3art3JNI") != -1) {
            // console.log("func_name="+symbol.name,"demangle_name="+demangle(symbol.name))
            JNIRegisterNatives_addr = symbol.address;
            if (temp_print) {
                console.log("JNIRegisterNatives_addr=", JNIRegisterNatives_addr)
            }
        }
        if (symbol.name.indexOf("ArtInterpreterToCompiledCodeBridge") != -1) {
            // console.log("func_name="+symbol.name,"demangle_name="+demangle(symbol.name))
            ArtInterpreterToCompiledCodeBridge_addr = symbol.address;
            if (temp_print) {
                console.log("ArtInterpreterToCompiledCodeBridge_addr=", ArtInterpreterToCompiledCodeBridge_addr)
            }
        }
        if (symbol.name.indexOf("ArtInterpreterToInterpreterBridge") != -1) {
            // console.log("func_name="+symbol.name,"demangle_name="+demangle(symbol.name))
            ArtInterpreterToInterpreterBridge_addr = symbol.address;
            if (temp_print) {
                console.log("ArtInterpreterToInterpreterBridge_addr=", ArtInterpreterToInterpreterBridge_addr)
            }
        }
        if (symbol.name.indexOf("artQuickToInterpreterBridge") != -1) {
            // console.log("func_name="+symbol.name,"demangle_name="+demangle(symbol.name))
            artQuickToInterpreterBridge_addr = symbol.address;
            if (temp_print) {
                console.log("artQuickToInterpreterBridge_addr=", artQuickToInterpreterBridge_addr)
            }
        }

        if (symbol.name.indexOf("artQuickGenericJniTrampoline") != -1) {
            // console.log("func_name="+symbol.name,"demangle_name="+demangle(symbol.name))
            artQuickGenericJniTrampoline_addr = symbol.address;
            if (temp_print) {
                console.log("artQuickGenericJniTrampoline_addr=", artQuickGenericJniTrampoline_addr)
            }
        }
    }
    console.log("native_init finished~" + new Array(20).join("-"))

}

function java_hook_wrapper() {
    Java.performNow(function () {
        var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
        if (currentApplication != null) {
            context = currentApplication.getApplicationContext();
            hook_java_user()
        } else {
            Java.use("android.app.ActivityThread").handleBindApplication.implementation = function (appBindData) {
                var result = this.handleBindApplication(appBindData)
                var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
                context = currentApplication.getApplicationContext();
                console.log("entered handleBindApplication")
                hook_java_user()
                return result
            }
            // Java.use("android.app.Activity").onCreate.overload('android.os.Bundle').implementation = function (bundle) {
            //     var result = this.onCreate(bundle)
            //     var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
            //     context = currentApplication.getApplicationContext();
            //     if (!is_hooked) {
            //         hook_java_user()
            //         is_hooked = true
            //     }
            //     return result
            // }
            // Java.use("android.content.ContextWrapper").attachBaseContext.implementation = function(context_){
            //     console.log("enter android.content.ContextWrapper.attachBaseContext")
            //     var result = this.attachBaseContext(context_)
            //     context = context_
            //     if(!is_hooked){
            //         hook_java_user()
            //         is_hooked=true
            //     }
            //     return result;
            // }
        }
        hook_java_system()
    })
}

function main() {
    java_init();
    java_hook_wrapper()
    native_init();
    native_hook(); // 去这里写native代码
}

//在这里写java的hook代码,不需要再包一层Java.perform了
function java_hook_real() {
    // console.log(Java.use("android.app.ActivityThread").class.getClassLoader())
    // console.log(Java.enumerateClassLoadersSync())

}



function jstring2Str(jstring) {
    var ret;
    Java.perform(function () {
        var String = Java.use("java.lang.String");
        ret = Java.cast(jstring, String);
    });
    return ret;
}

function jbyteArray2Array(jbyteArray) {
    var ret;
    Java.perform(function () {
        var b = Java.use('[B');
        var buffer = Java.cast(jbyteArray, b);
        ret = Java.array('byte', buffer);
    });
    return ret;
}

// 在这里写native的hook代码
function native_hook() {
    // hook_ArtMethod_RegisterNative()
    // hook_ArtMethod_Invoke()
    // hook_ArtInterpreterToInterpreterBridge()
    // hook_ArtInterpreterToCompiledCodeBridge()
}

// 在这里写java的hook代码
function hook_java_user() {
    dexdump_DexCache()
    // hookOneMethod("com.yaotong.crackme.MainActivity.onCreate")
}

function hook_java_system() {
    // hookOneMethod("android.app.Application.attach")
    // hookOneMethod("java.io.File.$init")
    // hookOneClass("android.app.ActivityThread")
    // hookOneMethod("android.content.ContextWrapper.attachBaseContext")
    // hookOneMethod("android.app.Activity.attachBaseContext")
    // hookOneMethod("java.io.File.exists")
    // hookOneMethod("java.lang.Runtime.exec")
}

setImmediate(main)
// 普通attach
// frida -UF -l v20220603_hook.js  -o out.log
// 普通spawn启动,需要修改包名
// frida -U -f com.lingzhiyi.temp -l v20220603_hook.js -o out.log --no-pause
// frida -U -f com.yaotong.crackme -l v20220603_hook.js -o out.log --no-pause
// frida -U -f com.vnpay.t2p -l v20220603_hook.js -o out.log --no-pause
// 使用ip加端口进行attach
// frida -H 192.168.3.30:27043 -l v20220603_hook.js -o out.log
// 使用ip加端口进行spawn,需要修改包名
// frida -H 192.168.3.30:27043 -f com.lingzhiyi.learnencryptedsp -l v20220603_hook.js -o out.log --no-pause
// 使用gadget模式,使用ip加端口的方式 安卓7直接在sdcard创建包名以加载gadget
// frida -H 192.168.3.32:27043 -n Lingzhiyi -l v20220603_hook.js -o out.log
// frida -H 127.0.0.1:27043 -f com.xingin.xhs --no-pause 
上一篇下一篇

猜你喜欢

热点阅读