Frida常用api大全

篇幅有限

完整内容及源码关注公众号:ReverseCode,发送

动静态函数主动调用

静态函数 use

function static() {
    Java.perform(function () {//只要是java的代码都要跑在Java.perform里面
        Java.use("com.example.junior.util.Utils").dip2px.implementation = function (context, float) {
            //return null;
            var result = this.dip2px(context, 100)
            console.log("context,float,result  ==> ", context, float, result);
            // 打印log
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
            return 26;
        }
         
        Java.use('com.xx.app.ShufferMap').show.implementation = function (map) {
             console.log(JSON.stringify(map));
            var hm = Java.use('java.util.HashMap').$new();
            hm.put("user","dajianbang");
            hm.put("pass","87654321");
            hm.put("code","123456");
            return this.show(hm);
        }     
        
        var myBytes = StringClass.$new("Hello World").getBytes();
        var base64Class = Java.use("android.util.Base64");
        var result = Java.use("com.xiaojianbang.app.RSA").encrypt(myBytes);
        console.log("result is :", result);
        console.log(JSON.stringify(result));
        console.log("base64 result is :", base64Class.encodeToString(result,0));        
    })
}

动态函数 choose

function dynamic(){
    Java.perform(function(){
        // hook 函数
        Java.choose("com.example.junior.CalculatorActivity",{
            onMatch:function(instance){
                console.log("found instance =>",instance);
                console.log("instance showText is =>",instance.clear("666"))
                console.log("instance showText is =>",instance.showText.value)
            },onComplete:function(){
                console.log('Search complete')
            }
        })

        // hook 对象
        Java.choose("com.xiaojianbang.app.Money",{
            onMatch : function(instance){
                console.log("find it!!", instance.getInfo());
            },
            
            onComplete: function(){
                console.log("compelete!!!");
            }
        })
    })
}

动静态变量修改

静态变量 use

function staticField(){
    Java.perform(function(){
        var divscale = Java.use("com.example.junior.util.Arith").DEF_DIV_SCALE.value;
        console.log("divscale1 is =>",divscale);
        Java.use("com.example.junior.util.Arith").DEF_DIV_SCALE.value=20;
        divscale = Java.use("com.example.junior.util.Arith").DEF_DIV_SCALE.value;
        console.log("divscale2 is =>",divscale);
    })
}

动态变量 choose

function dynamicField(){
    Java.perform(function(){
        Java.choose("com.example.junior.CalculatorActivity",{
            onMatch:function(instance){
                console.log("found instance =>",instance);
                console.log("instance showText is =>",instance.showText.value)
                instance.showText.value = "123"
            },onComplete:function(){
                console.log('Search complete')
            }
        })
    })
}

有参构造主动调用

// Utils.test(new Money(200,"美元"))
Java.perform(function () {
    var money = Java.use('com.xx.app.Money')  // 如果要自定义实例化就要获取并重写
    var utils = Java.use('com.xx.app.Utils');
    utils.test.overload("com.xx.app.Money").implementation = function (obj) { 
        var myBytes = StringClass.$new("Hello World").getBytes();
        // 重新实例化  $new()
        var mon = money.$new(999,'我的天')
        return mon.getInfo();  // 根据需求return
    }
});

Hook构造函数

// We need to replace .$init() instead of .$new(), since .$new() = .alloc() + .init()
Java.perform(function () {
    var money = Java.use('com.xx.app.Money');
    money.$init.implementation = function (a, b) {
        console.log("构造函数Hook中...", a, b);
        return this.$init(a, b);
    }

    // hook 构造方法 $init
    var MoneyClass = Java.use("com.kevin.app.Money");
    MoneyClass.$init.overload().implementation = function () {
        console.log("hook Money $init");
        this.$init();
    }
    
    var StringClass = Java.use("java.lang.String");
    var MoneyClass = Java.use("com.xiaojianbang.app.Money");
    MoneyClass.$init.overload('java.lang.String', 'int').implementation = function (x, y) {
        console.log('hook Money init');
        var myX = StringClass.new("Hello World!");
        var myY = 9999;
        this.$init(myX, myY);
    }       
});

枚举类所有方法

//Hook类的所有方法
Java.perform(function(){
    var md5 = Java.use("com.xxx.xxx.xxx");
    var methods = md5.class.getDeclaredMethods();
    for(var j = 0; j < methods.length; j++){
        var methodName = methods[j].getName();
        console.log(methodName);
        

    }
});

function main() {
    Java.perform(function () {
        // return String[] class name
        var classList = Java.enumerateLoadedClassesSync();
        for (var i = 0; i < classList.length; i++) {
            var targetClass = classList[i];
            if (targetClass.indexOf("com.xiaojianbang.app.Money") != -1) {
                console.log("hook the class: ", targetClass);
                var TargetClass = Java.use(targetClass);
                // 利用反射获取类中的所有方法
                var methodsList = TargetClass.class.getDeclaredMethods();
                for (var k = 0; k < methodsList.length; k++) {
                    console.log(methodsList[k].getName());
                    
                    // hook methodName 这个类的所有方法(难点在于每个方法的参数是不同的)
                    for (var k = 0; k < TargetClass[methodName].overloads.length; k++) {
                        TargetClass[methodName].overloads[k].implementation = function () {
                            // 这是 hook 逻辑
                            for (var i = 0; i < arguments.length; i++) {
                                console.log(arguments[i]);
                            }
                            return this[methodName].apply(this, arguments);  // 重新调用
                        }
                    }
                }
            }
        }
    })
}
 

function main(){
    Java.perform(function(){
        Java.enumerateLoadedClasses({
            onMatch: function(name,handle){
                if (name.indexOf("com.xiaojianbang.app.Money") != -1){
                    console.log(name,handle);
                    // 利用反射 获取类中的所有方法
                    var TargetClass = Java.use(name);
                    // return Method Object List
                    var methodsList = TargetClass.class.getDeclaredMethods(); 
                    for (var i = 0; i < methodsList.length; i++){
                        // Method Objection getName()
                        console.log(methodsList[i].getName());
                    }
                }
            },
            
            onComplete: function(){
                console.log("complete!!!")
            }
        })
    })
}

特殊不可见字符

当方法名被混淆时֏,打印出来所有的类名%D6%8F,用编码后的字符串hook

Java.perform(
    function x() {

        var targetClass = "com.example.hooktest.MainActivity";

        var hookCls = Java.use(targetClass);
        var methods = hookCls.class.getDeclaredMethods();

        for (var i in methods) {
            console.log(methods[i].toString());
            console.log(encodeURIComponent(methods[i].toString().replace(/^.*?\.([^\s\.\(\)]+)\(.*?$/, "$1")));
        }

        hookCls[decodeURIComponent("%D6%8F")].implementation = function (x) {
                console.log("original call: fun(" + x + ")");
                var result = this[decodeURIComponent("%D6%8F")](900);
                return result;
            }
    }
)

wallbreaker

function main(){
    Java.perform(function(){
        var Class = Java.use("java.lang.Class");
        
        function inspectObject(obj){
            var obj_class = Java.cast(obj.getClass(), Class);
            var fields = obj_class.getDeclaredFields();
            var methods = obj_class.getMethods();
            console.log("Inspectiong " + obj.getClass().toString());
            console.log("\t Fields:")
            for (var i in fields){
                console.log("\t\t" + fields[i].toString());
            }
            console.log("\t Methods:")
            for (var i in methods){
                console.log("\t\t" + methods[i].toString())
            }
        }

        Java.choose("com.baidu.lbs.waimai.WaimaiActivity",{
            onComplete: function(){
                console.log("complete!");
                
            },
            onMatch: function(instance){
                console.log("find instance", instance);
                inspectObject(instance);
            }
        })
    })
}

setImmediate(main)

枚举所有类

  Java.perform(function (){
    console.log("\n[*] enumerating classes...");
    Java.enumerateLoadedClasses({
      onMatch: function(_className){
        console.log("[*] found instance of '"+_className+"'");
      },
      onComplete: function(){
        console.log("[*] class enuemration complete");
      }
    });
  });

枚举接口实现

获取指定包下所有类的接口实现

function searchInterface(){
    Java.perform(function(){
        Java.enumerateLoadedClasses({
            onComplete: function(){},
            onMatch: function(name,handle){
                if (name.indexOf("com.r0ysue.a0526printout") > -1) { // 使用包名进行过滤
                    console.log("find class");
                    var targetClass = Java.use(name);
                    var interfaceList = targetClass.class.getInterfaces(); // 使用反射获取类实现的接口数组
                    if (interfaceList.length > 0) {
                        console.log(name) // 打印类名
                        for (var i in interfaceList) {
                            console.log("\t", interfaceList[i].toString()); // 直接打印接口名称
                        }
                    }
                }
            }
        })
    })
}

多个ClassLoader时枚举指定类所有关联的接口实现和父子类关系

Java.perform(function () {
    console.log("start")
    // 枚举classLoader设置含有关键类的classLoader
    Java.enumerateClassLoaders({
        onMatch: function (loader) {
            try {
                if (loader.findClass("com.jdd.motorfans.modules.detail.RecordFinishListener")) {
                    console.log("Successfully found loader")
                    console.log(loader);
                    Java.classFactory.loader = loader;
                }
            }
            catch (error) {
                console.log("find error:" + error)
            }
        },
        onComplete: function () {
            console.log("end1")
        }
    })
    // 枚举所有的类
    Java.enumerateLoadedClasses({
        onMatch: function (className) {
            if (className.toString().indexOf("RecordFinishListener") > 0 &&
                className.toString().indexOf("$") > 0
            ) {
                console.log("found => ", className)
                // 使用反射获取类实现的接口数组
                var interFaces = Java.use(className).class.getInterfaces();
                if(interFaces.length>0){
                    console.log("interface is => ");
                    for(var i in interFaces){
                        console.log("\t",interFaces[i].toString())
                    }
                }
                // 获取该类的父类名包含指定名称
                if (Java.use(className).class.getSuperclass()) {
                    var superClass = Java.use(className).class.getSuperclass().getName();
                    // console.log("superClass is => ",superClass);
                    if (superClass.indexOf("XC_MethodHook") > 0) {
                        console.log("found class is => ", className.toString())
                        traceClass(className);
                    }
                }

            }
        }, onComplete: function () {
            console.log("search completed!")
        }
    }) 
    console.log("end2")
})

Hook Char&Byte

Java.perform(function () {
    // 调用 自写dex
    Java.openClassFile("/data/local/tmp/r0gson.dex").load();
    const gson = Java.use('com.r0ysue.gson.Gson');

    // 打印CharArray数组
    Java.use("java.util.Arrays").toString.overload('[C').implementation = function(charArray){
        // Java.array('char', [ '一','去','二','三','里' ]);
        // Java.use('java.lang.String').$new(Java.array('char', [ '烟','村','四','五','家'])) 
        // Java.array("java.lang.String",["一","二","三"]);
        var result = this.toString(charArray);
        var result1 = JSON.stringify(charArray);
        console.log("charArray,result:",charArray,result)
        console.log(ArrayClass.toString(result));
        console.log("charArray Object Object:",gson.$new().toJson(charArray));
        return result;
    }
    
    // 打印char字符
    var CharClass = Java.use("java.lang.Character");
    CharClass.toString.overload("char").implementation = function(inputChar){
        var result = this.toString(inputChar);
        console.log("inputChar, result: ", inputChar, result);
        return result;
    }    

    // byteArray
    Java.use("java.util.Arrays").toString.overload('[B').implementation = function(byteArray){
        var result = this.toString(byteArray);
        var result1 = JSON.stringify(byteArray);
        console.log("byteArray,result):",byteArray,result)
        console.log("byteArray Object Object:",gson.$new().toJson(byteArray));
        return result;
    }
    
    var StringClass = Java.use("java.lang.String");
    var byteArray = StringClass.$new("Hello World").getBytes();
    Java.openClassFile("/data/local/tmp/r0gson.dex").load();
    var gson = Java.use("com.r0ysue.gson.Gson");
    console.log(gson.$new().toJson(byteArray));
    // // console byte[]
    var ByteString = Java.use("com.android.okhttp.okio.ByteString");
    console.log(ByteString.of(byteArray).hex()); // byte转16进制字符串
    // // 创建自定义Java数组 并打印
    var MyArray = Java.array("byte",[13,4,4,2]);
    console.log(gson.$new().toJson(MyArray));

});

Hook Map

遍历打印
function main() {
    Java.perform(function () {
        var targetClass = Java.use("com.xiaojianbang.app.ShufferMap");
        targetClass.show.implementation = function (map) {
            // 遍历 map
            var result = "";
            var it = map.keySet().iterator();
            while (it.hasNext()) {
                var keyStr = it.next();
                var valueStr = map.get(keyStr);
                result += valueStr;
            }
            console.log("result :", result);

            // 修改 map
            map.put("pass", "fxxk");
            map.put("code", "Hello World");
            console.log(JSON.stringify(map));

            return this.show(map);
        }
    })
}

setImmediate(main);
cast打印 HashMap
function main() {
    Java.perform(function () {
        var HashMapNode = Java.use("java.util.HashMap$Node");
        var targetClass = Java.use("com.xiaojianbang.app.ShufferMap");

        var targetClass.show.implementation = function (map) {
            var result = "";
            var iterator = map.entrySet().iterator();
            while (iterator.hasNext()) {
                console.log("entry", iterator.next());
                var entry = Java.cast(iterator.next(), HashMapNode);
                console.log(entry.getKey());
                console.log(entry.getValue());
                return += entry.getValue();
            }

            console.log("result is :", result);
        }
    })
}

function main(){
    Java.perform(function(){
        var targetClass = Java.use("com.xiaojianbang.app.ShufferMap");
        var HashMap = Java.use('java.util.HashMap');
        targetClass.show.implementation = function(map){
            // 直接调用 toString()
            var args_map = Java.cast(param_hm, HashMap);
            console.log("打印hashmap: -> " + map.toString() + args_map.toString());
            return this.show.apply(this,arguments);
        }
    })
}

setImmediate(main);

Hook 重载

function hookdecodeimgkey() {
    Java.perform(function () {
        var base64 = Java.use("android.util.Base64")
        Java.use("com.ilulutv.fulao2.other.i.b").b.overload('[B', '[B', 'java.lang.String').implementation = function (key, iv, image) {
            var result = this.b(key, iv, image);
            console.log("key", base64.encodeToString(key, 0));
            console.log("iv", base64.encodeToString(iv, 0));
            return result;
        }
        
        var UtilsClass = Java.use("com.kevin.app.Utils");
        // 重载无参方法
        UtilsClass.test.overload().implementation = function () {
            console.log("hook overload no args");
            return this.test();
        }
        
        // 重载有参方法 - 基础数据类型
        UtilsClass.test.overload('int').implementation = function(num){
            console.log("hook overload int args");
            var myNum = 9999;
            var oriResult = this.test(num);
            console.log("oriResult is :" + oriResult);
            return this.test(myNum);
        }
        
        // 重载有参方法 - 引用数据类型
        UtilsClass.test.overload('com.kevin.app.Money').implementation = function(money){
            console.log("hook Money args");
            return this.test(money);
        }
        
        // hook 指定方法的所有重载
        var ClassName = Java.use("com.xiaojianbang.app.Utils");
        var overloadsLength = ClassName.test.overloads.length;
        for (var i = 0; i < overloadsLength; i++){
            ClassName.test.overloads[i].implementation = function () {
                // 遍历打印 arguments 
                for (var a = 0; a < arguments.length; a++){
                    console.log(a + " : " + arguments[a]);
                }
                // 调用原方法
                return this.test.apply(this,arguments);
            }
        }        
    })
}

Hook 内部类

function main(){
    Java.perfor(function(){
        // hook 内部类
        // 内部类使用$进行分隔 不使用.
        var InnerClass = Java.use("com.xiaojianbang.app.Money$innerClass");
        // 重写内部类的 $init 方法
        InnerClass.$init.overload("java.lang.String","int").implementation = function(x,y){
            console.log("x: ",x);
            console.log("y: ",y);
            this.$init(x,y);
        }
    })
}

setImmediate(main)

Hook 匿名类

// 接口, 抽象类, 不可以被new
// 接口, 抽象类 要使用必须要实例化, 实例化不是通过new, 而是通过实现接口方法, 继承抽象类等方式
// new __接口__{} 可以理解成 new 了一个实现接口的匿名类, 在匿名类的内部(花括号内),实现了这个接口

function main(){
    Java.perform(function(){
        // hook 匿名类
        // 匿名类在 smail中以 $1, $2 等方式存在, 需要通过 java 行号去 smail 找到准确的匿名类名称 
        var NiMingClass = Java.use("com.xiaojianbang.app.MainActivity$1");
        NiMingClass.getInfo.implementation = function (){
            return "kevin change 匿名类";
        }
    })
}

setImmediate(main)

Hook 枚举类

function enumPrint(){
    Java.perform(function(){
        Java.choose("com.r0ysue.a0526printout.Signal",{
            onComplete: function(){},
            onMatch: function(instance){
                console.log('find it ,',instance);
                console.log(instance.class.getName());
            }
        })
    })
}

Hook 动态加载dex

function main(){
    Java.perform(function(){
        Java.enumerateClassLoaders({
            onMatch : function(loader){
                try {
                    // loadClass or findClass 并指定classLoader
                    if (loader.loadClass("com.xiaojianbang.app.Dynamic")){
                        Java.classFactory.loader = loader;
                        var hookClass = Java.use("com.xiaojianbang.app.Dynamic");
                        console.log("success hook it :", hookClass);
                    }
                } catch (error) {
                }
            },
            
            onComplete: function () {
                console.log("complete !!! ")
            }
        })
    })
}

setImmediate(main);

经常在加壳的 app 中, 没办法正确找到正常加载 app 类的 classloader

function hook() {
    Java.perform(function () {
        Java.enumerateClassLoadersSync().forEach(function (classloader) {
            try {
                console.log("classloader", classloader);
                classloader.loadClass("com.kanxue.encrypt01.MainActivity");
                Java.classFactory.loader = classloader;
                var mainActivityClass = Java.use("com.kanxue.encrypt01.MainActivity");
                console.log("mainActivityClass", mainActivityClass);
            } catch (error) {
                console.log("error", error);
            }
        });
    })
}

trace类调用栈

function uniqBy(array, key) {
    var seen = {};
    return array.filter(function (item) {
        var k = key(item);
        return seen.hasOwnProperty(k) ? false : (seen[k] = true);
    });
}

// trace a specific Java Method
function traceMethod(targetClassMethod) {
    var delim = targetClassMethod.lastIndexOf(".");
    if (delim === -1) return;

    var targetClass = targetClassMethod.slice(0, delim)
    var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length)

    var hook = Java.use(targetClass);
    var overloadCount = hook[targetMethod].overloads.length;

    console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]");


    
    // hook all class_method
    for (var i = 0; i < overloadCount; i++) {

        hook[targetMethod].overloads[i].implementation = function () {
            console.warn("\n*** entered " + targetClassMethod);

            // print backtrace
            // Java.perform(function() {
            //  var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
            //  console.log("\nBacktrace:\n" + bt);
            // });

            // print args
            if (arguments.length) console.log();
            for (var j = 0; j < arguments.length; j++) {
                console.log("arg[" + j + "]: " + arguments[j]);

            }

            // print retval
            var retval = this[targetMethod].apply(this, arguments); // rare crash (Frida bug?)
            console.log("\nretval: " + retval);
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
            console.warn("\n*** exiting " + targetClassMethod);
            return retval;
        }
    }
    

}

function traceClass(targetClass) {
    //Java.use是新建一个对象哈,大家还记得么?
    var hook = Java.use(targetClass);
    //利用反射的方式,拿到当前类的所有方法
    var methods = hook.class.getDeclaredMethods();
    // var methods = hook.class.getMethods();
    //建完对象之后记得将对象释放掉哈
    hook.$dispose;
    //将方法名保存到数组中
    var parsedMethods = [];
    methods.forEach(function (method) {
        parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]);
    });
    //去掉一些重复的值
    var targets = uniqBy(parsedMethods, JSON.stringify);
    //对数组中所有的方法进行hook,traceMethod也就是第一小节的内容
    targets.forEach(function (targetMethod) {
        traceMethod(targetClass + "." + targetMethod);
    });
}

调用栈打印

function printStacks(name){
    console.log("====== printStacks start ====== " + name + "==============================")
    
    // sample 1
    var throwable = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
    console.log(throwable);

    // sample 2
    var exception = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
    console.log(exception);
    
    console.log("====== printStacks end ======== " + name + "==============================")
}

手动注册类

Java.perform(function () {

    var Runnable = Java.use("java.lang.Runnable");
    var saveImg = Java.registerClass({
        name: "com.roysue.runnable",
        implements: [Runnable],
        fields: {
            bm: "android.graphics.Bitmap",
        },
        methods: {
            $init: [{
                returnType: "void",
                argumentTypes: ["android.graphics.Bitmap"],
                implementation: function (bitmap) {
                    this.bm.value = bitmap;
                }
            }],
            run: function () {
                var path = "/sdcard/Download/tmp/" + guid() + ".jpg"
                console.log("path=> ", path)
                var file = Java.use("java.io.File").$new(path)
                var fos = Java.use("java.io.FileOutputStream").$new(file);

                this.bm.value.compress(Java.use("android.graphics.Bitmap$CompressFormat").JPEG.value, 100, fos)
                fos.flush();
                fos.close();

            }
        }
    });


    Java.use("android.graphics.BitmapFactory").decodeByteArray.overload('[B', 'int', 'int', 'android.graphics.BitmapFactory$Options').implementation = function (data, offset, length, opts) {
        var result = this.decodeByteArray(data, offset, length, opts);
        var ByteString = Java.use("com.android.okhttp.okio.ByteString");

        var runnable = saveImg.$new(result);
        runnable.run()
        return result;
    }
})



Java.perform(function() {
   // https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_SECURE
   var FLAG_SECURE = 0x2000;
   var Runnable = Java.use("java.lang.Runnable");
   var DisableSecureRunnable = Java.registerClass({
      name: "me.bhamza.DisableSecureRunnable",
      implements: [Runnable],
      fields: {
          activity: "android.app.Activity",
       },
       methods: {
          $init: [{
             returnType: "void",
             argumentTypes: ["android.app.Activity"],
             implementation: function (activity) {
                this.activity.value = activity;
             }
          }],
          run: function() {
             var flags = this.activity.value.getWindow().getAttributes().flags.value; // get current value
             flags &= ~FLAG_SECURE; // toggle it
             this.activity.value.getWindow().setFlags(flags, FLAG_SECURE); // disable it!
             console.log("Done disabling SECURE flag...");
          }
       }
    });

    Java.choose("com.example.app.FlagSecureTestActivity", {
       "onMatch": function (instance) {
          var runnable = DisableSecureRunnable.$new(instance);
          instance.runOnUiThread(runnable);
       },
       "onComplete": function () {}
    });
 });

Hook Click

var jclazz = null;
var jobj = null;

function getObjClassName(obj) {
    if (!jclazz) {
        var jclazz = Java.use("java.lang.Class");
    }
    if (!jobj) {
        var jobj = Java.use("java.lang.Object");
    }
    return jclazz.getName.call(jobj.getClass.call(obj));
}

function watch(obj, mtdName) {
    var listener_name = getObjClassName(obj);
    var target = Java.use(listener_name);
    if (!target || !mtdName in target) {
        return;
    }
    // send("[WatchEvent] hooking " + mtdName + ": " + listener_name);
    target[mtdName].overloads.forEach(function (overload) {
        overload.implementation = function () {
            //send("[WatchEvent] " + mtdName + ": " + getObjClassName(this));
            console.log("[WatchEvent] " + mtdName + ": " + getObjClassName(this))
            return this[mtdName].apply(this, arguments);
        };
    })
}

function OnClickListener() {
    Java.perform(function () {

        //以spawn启动进程的模式来attach的话
        Java.use("android.view.View").setOnClickListener.implementation = function (listener) {
            if (listener != null) {
                watch(listener, 'onClick');
            }
            return this.setOnClickListener(listener);
        };

        //如果frida以attach的模式进行attch的话
        Java.choose("android.view.View$ListenerInfo", {
            onMatch: function (instance) {
                instance = instance.mOnClickListener.value;
                if (instance) {
                    console.log("mOnClickListener name is :" + getObjClassName(instance));
                    watch(instance, 'onClick');
                }
            },
            onComplete: function () {
            }
        })
    })
}
setImmediate(OnClickListener);

Hook Activity

Java.perform(function () {
    var Activity = Java.use("android.app.Activity");
    //console.log(Object.getOwnPropertyNames(Activity));
    Activity.startActivity.overload('android.content.Intent').implementation=function(p1){
        console.log("Hooking android.app.Activity.startActivity(p1) successfully,p1="+p1);
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
        console.log(decodeURIComponent(p1.toUri(256)));
        this.startActivity(p1);
    }
    Activity.startActivity.overload('android.content.Intent', 'android.os.Bundle').implementation=function(p1,p2){
        console.log("Hooking android.app.Activity.startActivity(p1,p2) successfully,p1="+p1+",p2="+p2);
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
        console.log(decodeURIComponent(p1.toUri(256)));
        this.startActivity(p1,p2);
    }
    Activity.startService.overload('android.content.Intent').implementation=function(p1){
        console.log("Hooking android.app.Activity.startService(p1) successfully,p1="+p1);
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
        console.log(decodeURIComponent(p1.toUri(256)));
        this.startService(p1);
    }
})

frida主线程运行

使用一些方法的时候出现报错 on a thread that has not called Looper.prepare()

Java.perform(function() {
  var Toast = Java.use('android.widget.Toast');
  var currentApplication = Java.use('android.app.ActivityThread').currentApplication(); 
  var context = currentApplication.getApplicationContext();

  Java.scheduleOnMainThread(function() {
    Toast.makeText(context, "Hello World", Toast.LENGTH_LONG.value).show();
  })
})

过滤打印

function hook_lnf() {
    var activate = false;

    Java.perform(function(){
        var hashmapClass = Java.use("java.util.HashMap");
        hashmapClass.put.implementation = function(key,value){
            if (activate){
                console.log("key:", key, "value:", value);
            }
            return this.put(key,value);
        };
    });

    Java.perform(function () {
        var lnfClazz = Java.use("tb.lnf");
        lnfClazz.a.overload('java.util.HashMap', 'java.util.HashMap', 'java.lang.String',
            'java.lang.String', 'boolean').implementation = function (hashmap, hashmap2, str, str2, z) {
                printHashMap("hashmap", hashmap);
                printHashMap("hashmap2", hashmap2);
                console.log("str", str);
                console.log("str2", str2);
                console.log("boolean", z);
                activate = true;
                var result = this.a(hashmap, hashmap2, str, str2, z);
                activate = false
                printHashMap("result", result);
                return result;
            };
    })
}

禁止退出

function hookExit(){
    Java.perform(function(){
        console.log("[*] Starting hook exit");
        var exitClass = Java.use("java.lang.System");
        exitClass.exit.implementation = function(){
            console.log("[*] System.exit.called");
        }
        console.log("[*] hooking calls to System.exit");
    })
}

setImmediate(hookExit);

修改设备参数

// frida hook 修改设备参数
Java.perform(function() {
    var TelephonyManager = Java.use("android.telephony.TelephonyManager");

    //IMEI hook
    TelephonyManager.getDeviceId.overload().implementation = function () {
               console.log("[*]Called - getDeviceId()");
               var temp = this.getDeviceId();
               console.log("real IMEI: "+temp);
               return "867979021642856";
    };
    // muti IMEI
    TelephonyManager.getDeviceId.overload('int').implementation = function (p) {
               console.log("[*]Called - getDeviceId(int) param is"+p);
               var temp = this.getDeviceId(p);
               console.log("real IMEI "+p+": "+temp);
               return "867979021642856";
    };

    //IMSI hook
    TelephonyManager.getSimSerialNumber.overload().implementation = function () {
               console.log("[*]Called - getSimSerialNumber(String)");
               var temp = this.getSimSerialNumber();
               console.log("real IMSI: "+temp);
               return "123456789";
    };
    //////////////////////////////////////

    //ANDOID_ID hook
    var Secure = Java.use("android.provider.Settings$Secure");
    Secure.getString.implementation = function (p1,p2) {
        if(p2.indexOf("android_id")<0) return this.getString(p1,p2);
        console.log("[*]Called - get android_ID, param is:"+p2);
        var temp = this.getString(p1,p2);
        console.log("real Android_ID: "+temp);
        return "844de23bfcf93801";

    }

    //android的hidden API,需要通过反射调用
    var SP = Java.use("android.os.SystemProperties");
    SP.get.overload('java.lang.String').implementation = function (p1) {
        var tmp = this.get(p1);
        console.log("[*]"+p1+" : "+tmp);

        return tmp;
    }
    SP.get.overload('java.lang.String', 'java.lang.String').implementation = function (p1,p2) {
        
        
        var tmp = this.get(p1,p2)
        console.log("[*]"+p1+","+p2+" : "+tmp);
        return tmp;
    } 
    // hook MAC
    var wifi = Java.use("android.net.wifi.WifiInfo");
    wifi.getMacAddress.implementation = function () {
        var tmp = this.getMacAddress();
        console.log("[*]real MAC: "+tmp);
        return tmp;
    }
    
})

请求调用栈

var class_Socket = Java.use("java.net.Socket");
class_Socket.getOutputStream.overload().implementation = function(){
    send("getOutputSteam");
    var result = this.getOutputStream();
    var bt = Java.use("android.util.Log").getStackTraceString(
        Java.use("java.lang.Exception").$new();
    )
    console.log("Backtrace:" + bt);
    send(result);
    return result;
}

上下文Context

function getContext(){
    Java.perform(function(){
        var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
        console.log(currentApplication);
        var context = currentApplication.getApplicationContext();
        console.log(context);
        var packageName = context.getPackageName();
        console.log(packageName);
        console.log(currentApplication.getPackageName());
    })
}

RPC

frida 传递参数
function main(){
    Java.perform(function () {
        console.log("enter perform");
        // 获取要hook的类
        var TextViewClass = Java.use("android.widget.TextView");
        // 要hook的方法
        TextViewClass.setText.overload('java.lang.CharSequence').implementation = function (ori_input) {
            console.log('enter', 'java.lang.CharSequence');
            console.log('ori_input',ori_input.toString());

            // 定义用于接受python传参的data
            var receive_data;
            // 将原参数传递给python 在python中进行处理
            send(ori_input.toString());
            // recv 从python接收传递的内容 默认传过来的是个json对象
            recv(function (json_data) {
                console.log('data from python ' + json_data.data);
                receive_data = json_data.data;
                console.log(typeof (receive_data));
            }).wait(); //wait() 等待python处理 阻塞

            // 转java字符串
            receive_data = Java.use("java.lang.String").$new(receive_data);
            this.setText(receive_data);
        };
    })
}

setImmediate(main);
python 处理收到的参数
# -*- coding: utf-8 -*-
__author__ = "K"
__time__ = "2020-08-06 09:48"

import sys
import time
import base64
import frida
from loguru import logger

def on_message(message,data):
    logger.info(str(message)) # dict
    logger.info(str(data) if data else "None")

    if message['type'] == 'error':
        logger.error('error:' + str(message['description']))
        logger.error('stack: ' + str(message['stack']))

    if message['type'] == 'send':
        logger.info('get message [*] --> ' + message['payload'])

        payload = message['payload']
        # 处理逻辑 sending to the server: YWFhOmJiYg==
        tmp = payload.split(':')
        sts = tmp[0]
        need_to_db64 = tmp[1]
        user_pass = base64.b64decode(need_to_db64.encode()).decode()

        mine_str = 'admin' + ':' + user_pass.split(':')[-1]
        mine_b64_str = base64.b64encode(mine_str.encode()).decode()
        mine_b64_str = sts + mine_b64_str
        logger.info(mine_b64_str)

        # python返回数据给js script.post
        script.post({'data':mine_b64_str})
        logger.info('python complete')

device = frida.get_usb_device()
# pid = device.spawn(['com.kevin.demo04'])
# time.sleep(1)
session = device.attach('com.kevin.demo02')
with open('./hulianhutong.js','r') as f:
    script = session.create_script(f.read())

script.on("message",on_message)
script.load()
input()

强制类型转换

// Java.cast() 子类可以强转成父类, 父类不能转成子类
// 可以使用Java.cast()将子类强转成父类, 再调用父类的动态方法

function castDemo(){
    Java.perform(function(){
        var JuiceHandle = null; // 用来存储内存中找到的Juice对象
        var WaterClass = Java.use("com.r0ysue.a0526printout.Water");
        
        Java.choose("com.r0ysue.a0526printout.Juice",{
            onComplete: function(){},
             onMatch: function(instance){
                JuiceHandle = instance;
                console.log("instance:", instance);
                // 调用Juice对象的方法
                console.log(JuiceHandle.fillEnergy());
                // 子类Juice转父类Water 并调用父类的动态方法
                var WaterInstance = Java.cast(JuiceHandle,WaterClass);
                console.log(WaterInstance.still(WaterInstance));
            }
        })
    })
}

常见算法hook

Java.perform(function () {
    var secretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');
    secretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function (a, b) {
        showStacks();
        var result = this.$init(a, b);
        send("======================================");
        send("算法名:" + b + "|Dec密钥:" + bytesToString(a));
        send("算法名:" + b + "|Hex密钥:" + bytesToHex(a));
        return result;
    }
    var mac = Java.use('javax.crypto.Mac');
    mac.getInstance.overload('java.lang.String').implementation = function (a) {
        showStacks();
        var result = this.getInstance(a);
        send("======================================");
        send("算法名:" + a);
        return result;
    }
    mac.update.overload('[B').implementation = function (a) {
        showStacks();
        this.update(a);
        send("======================================");
        send("update:" + bytesToString(a))
    }
    mac.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
        showStacks();
        this.update(a, b, c)
        send("======================================");
        send("update:" + bytesToString(a) + "|" + b + "|" + c);
    }
    mac.doFinal.overload().implementation = function () {
        showStacks();
        var result = this.doFinal();
        send("======================================");
        send("doFinal结果:" + bytesToHex(result));
        send("doFinal结果:" + bytesToBase64(result));
        return result;
    }
    mac.doFinal.overload('[B').implementation = function (a) {
        showStacks();
        var result = this.doFinal(a);
        send("======================================");
        send("doFinal参数:" + bytesToString(a));
        send("doFinal结果:" + bytesToHex(result));
        send("doFinal结果:" + bytesToBase64(result));
        return result;
    }
    var md = Java.use('java.security.MessageDigest');
    md.getInstance.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {
        showStacks();
        send("======================================");
        send("算法名:" + a);
        return this.getInstance(a, b);
    }
    md.getInstance.overload('java.lang.String').implementation = function (a) {
        showStacks();
        send("======================================");
        send("算法名:" + a);
        return this.getInstance(a);
    }
    md.update.overload('[B').implementation = function (a) {
        showStacks();
        send("======================================");
        send("update:" + bytesToString(a))
        return this.update(a);
    }
    md.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
        showStacks();
        send("======================================");
        send("update:" + bytesToString(a) + "|" + b + "|" + c);
        return this.update(a, b, c);
    }
    md.digest.overload().implementation = function () {
        showStacks();
        send("======================================");
        var result = this.digest();
        send("digest结果:" + bytesToHex(result));
        send("digest结果:" + bytesToBase64(result));
        return result;
    }
    md.digest.overload('[B').implementation = function (a) {
        showStacks();
        send("======================================");
        send("digest参数:" + bytesToString(a));
        var result = this.digest(a);
        send("digest结果:" + bytesToHex(result));
        send("digest结果:" + bytesToBase64(result));
        return result;
    }
    var ivParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');
    ivParameterSpec.$init.overload('[B').implementation = function (a) {
        showStacks();
        var result = this.$init(a);
        send("======================================");
        send("iv向量:" + bytesToString(a));
        send("iv向量:" + bytesToHex(a));
        return result;
    }
    var cipher = Java.use('javax.crypto.Cipher');
    cipher.getInstance.overload('java.lang.String').implementation = function (a) {
        showStacks();
        var result = this.getInstance(a);
        send("======================================");
        send("模式填充:" + a);
        return result;
    }
    cipher.update.overload('[B').implementation = function (a) {
        showStacks();
        var result = this.update(a);
        send("======================================");
        send("update:" + bytesToString(a));
        return result;
    }
    cipher.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
        showStacks();
        var result = this.update(a, b, c);
        send("======================================");
        send("update:" + bytesToString(a) + "|" + b + "|" + c);
        return result;
    }
    cipher.doFinal.overload().implementation = function () {
        showStacks();
        var result = this.doFinal();
        send("======================================");
        send("doFinal结果:" + bytesToHex(result));
        send("doFinal结果:" + bytesToBase64(result));
        return result;
    }
    cipher.doFinal.overload('[B').implementation = function (a) {
        showStacks();
        var result = this.doFinal(a);
        send("======================================");
        send("doFinal参数:" + bytesToString(a));
        send("doFinal结果:" + bytesToHex(result));
        send("doFinal结果:" + bytesToBase64(result));
        return result;
    }
    var x509EncodedKeySpec = Java.use('java.security.spec.X509EncodedKeySpec');
    x509EncodedKeySpec.$init.overload('[B').implementation = function (a) {
        showStacks();
        var result = this.$init(a);
        send("======================================");
        send("RSA密钥:" + bytesToBase64(a));
        return result;
    }
    var rSAPublicKeySpec = Java.use('java.security.spec.RSAPublicKeySpec');
    rSAPublicKeySpec.$init.overload('java.math.BigInteger', 'java.math.BigInteger').implementation = function (a, b) {
        showStacks();
        var result = this.$init(a, b);
        send("======================================");
        //send("RSA密钥:" + bytesToBase64(a));
        send("RSA密钥N:" + a.toString(16));
        send("RSA密钥E:" + b.toString(16));
        return result;
    }
});

base64实现

# -*- coding: utf-8 -*-
import base64

DEFAULT = 0  # 默认模式, 每行不超过76个字符
NO_PADDING = 1  # 移除最后的=
NO_WRAP = 2  # 不换行,一行输出
CRLF = 4  # 采用win上的换行符
URL_SAVE = 8  # 采用urlsafe


def decode(content: str, flag: int) -> bytes:
    missing_padding = len(content) % 4
    if missing_padding != 0:
        content = content.ljust(len(content) + (4 - missing_padding), "=")

    if flag & URL_SAVE:
        result = base64.urlsafe_b64decode(content.encode("utf-8"))
    else:
        result = base64.b64decode(content.encode("utf-8"))
    return result


def encode(content: bytes, flag: int) -> str:
    need_wrap = True
    need_padding = True
    lf = "\n"

    if flag & NO_WRAP:
        need_wrap = False
    if flag & NO_PADDING:
        need_padding = False
    if flag & CRLF:
        lf = "\r\n"

    if flag & URL_SAVE:
        result = base64.urlsafe_b64encode(content).decode("utf-8")
    else:
        result = base64.b64encode(content).decode("utf-8")

    if not need_padding:
        result = result.rstrip("=")

    if need_wrap:
        n = 76
        output = lf.join([result[i:i + n] for i in range(0, len(result), n)])
    else:
        output = result

    return output

常用转换模板

//工具相关函数
var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
    base64DecodeChars = new Array((-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), 62, (-1), (-1), (-1), 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, (-1), (-1), (-1), (-1), (-1), (-1), (-1), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, (-1), (-1), (-1), (-1), (-1), (-1), 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, (-1), (-1), (-1), (-1), (-1));

function stringToBase64(e) {
    var r, a, c, h, o, t;
    for (c = e.length, a = 0, r = ''; a < c;) {
        if (h = 255 & e.charCodeAt(a++), a == c) {
            r += base64EncodeChars.charAt(h >> 2),
                r += base64EncodeChars.charAt((3 & h) << 4),
                r += '==';
            break
        }
        if (o = e.charCodeAt(a++), a == c) {
            r += base64EncodeChars.charAt(h >> 2),
                r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
                r += base64EncodeChars.charAt((15 & o) << 2),
                r += '=';
            break
        }
        t = e.charCodeAt(a++),
            r += base64EncodeChars.charAt(h >> 2),
            r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
            r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),
            r += base64EncodeChars.charAt(63 & t)
    }
    return r
}

function base64ToString(e) {
    var r, a, c, h, o, t, d;
    for (t = e.length, o = 0, d = ''; o < t;) {
        do
            r = base64DecodeChars[255 & e.charCodeAt(o++)];
        while (o < t && r == -1);
        if (r == -1)
            break;
        do
            a = base64DecodeChars[255 & e.charCodeAt(o++)];
        while (o < t && a == -1);
        if (a == -1)
            break;
        d += String.fromCharCode(r << 2 | (48 & a) >> 4);
        do {
            if (c = 255 & e.charCodeAt(o++), 61 == c)
                return d;
            c = base64DecodeChars[c]
        } while (o < t && c == -1);
        if (c == -1)
            break;
        d += String.fromCharCode((15 & a) << 4 | (60 & c) >> 2);
        do {
            if (h = 255 & e.charCodeAt(o++), 61 == h)
                return d;
            h = base64DecodeChars[h]
        } while (o < t && h == -1);
        if (h == -1)
            break;
        d += String.fromCharCode((3 & c) << 6 | h)
    }
    return d
}

function hexToBase64(str) {
    return base64Encode(String.fromCharCode.apply(null, str.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ")));
}

function base64ToHex(str) {
    for (var i = 0, bin = base64Decode(str.replace(/[ \r\n]+$/, "")), hex = []; i < bin.length; ++i) {
        var tmp = bin.charCodeAt(i).toString(16);
        if (tmp.length === 1)
            tmp = "0" + tmp;
        hex[hex.length] = tmp;
    }
    return hex.join("");
}

function hexToBytes(str) {
    var pos = 0;
    var len = str.length;
    if (len % 2 != 0) {
        return null;
    }
    len /= 2;
    var hexA = new Array();
    for (var i = 0; i < len; i++) {
        var s = str.substr(pos, 2);
        var v = parseInt(s, 16);
        hexA.push(v);
        pos += 2;
    }
    return hexA;
}

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;
}

function stringToHex(str) {
    var val = "";
    for (var i = 0; i < str.length; i++) {
        if (val == "")
            val = str.charCodeAt(i).toString(16);
        else
            val += str.charCodeAt(i).toString(16);
    }
    return val
}

function stringToBytes(str) {
    var ch, st, re = [];
    for (var i = 0; i < str.length; i++) {
        ch = str.charCodeAt(i);
        st = [];
        do {
            st.push(ch & 0xFF);
            ch = ch >> 8;
        }
        while (ch);
        re = re.concat(st.reverse());
    }
    return re;
}

//将byte[]转成String的方法
function bytesToString(arr) {
    var str = '';
    arr = new Uint8Array(arr);
    for (var i in arr) {
        str += String.fromCharCode(arr[i]);
    }
    return str;
}

function bytesToBase64(e) {
    var r, a, c, h, o, t;
    for (c = e.length, a = 0, r = ''; a < c;) {
        if (h = 255 & e[a++], a == c) {
            r += base64EncodeChars.charAt(h >> 2),
                r += base64EncodeChars.charAt((3 & h) << 4),
                r += '==';
            break
        }
        if (o = e[a++], a == c) {
            r += base64EncodeChars.charAt(h >> 2),
                r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
                r += base64EncodeChars.charAt((15 & o) << 2),
                r += '=';
            break
        }
        t = e[a++],
            r += base64EncodeChars.charAt(h >> 2),
            r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
            r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),
            r += base64EncodeChars.charAt(63 & t)
    }
    return r
}

function base64ToBytes(e) {
    var r, a, c, h, o, t, d;
    for (t = e.length, o = 0, d = []; o < t;) {
        do
            r = base64DecodeChars[255 & e.charCodeAt(o++)];
        while (o < t && r == -1);
        if (r == -1)
            break;
        do
            a = base64DecodeChars[255 & e.charCodeAt(o++)];
        while (o < t && a == -1);
        if (a == -1)
            break;
        d.push(r << 2 | (48 & a) >> 4);
        do {
            if (c = 255 & e.charCodeAt(o++), 61 == c)
                return d;
            c = base64DecodeChars[c]
        } while (o < t && c == -1);
        if (c == -1)
            break;
        d.push((15 & a) << 4 | (60 & c) >> 2);
        do {
            if (h = 255 & e.charCodeAt(o++), 61 == h)
                return d;
            h = base64DecodeChars[h]
        } while (o < t && h == -1);
        if (h == -1)
            break;
        d.push((3 & c) << 6 | h)
    }
    return d
}



// 打印log
function showStacks() {
    Java.perform(function () {
        send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
    });
}

// 字节数组转hex字符串
function bytesToHex(arr) {
    var str = "";
    for (var i = 0; i < arr.length; i++) {
        var tmp = arr[i];
        if (tmp < 0) {
            tmp = (255 + tmp + 1).toString(16);
        } else {
            tmp = tmp.toString(16);
        }
        if (tmp.length == 1) {
            tmp = "0" + tmp;
        }
        str += tmp;
    }
    return str;
}

function bytesToBase64(arr) {
    var str = "";
    for (var i = 0; i < arr.length; i++) {
        var tmp = arr[i];
        if (tmp < 0) {
            tmp = (255 + tmp + 1).toString(16);
        } else {
            tmp = tmp.toString(16);
        }
        if (tmp.length == 1) {
            tmp = "0" + tmp;
        }
        str += tmp;
    }
    return str;
}

function bytesToString(arr) {
    var str = "";
    for (var i = 0; i < arr.length; i++) {
        var tmp = arr[i];
        if (tmp < 0) {
            tmp = (255 + tmp + 1).toString(16);
        } else {
            tmp = tmp.toString(16);
        }
        if (tmp.length == 1) {
            tmp = "0" + tmp;
        }
        str += tmp;
    }
    return str;
}
function byteToHexString(uint8arr) {
    if (!uint8arr) {
        return '';
    }
    var hexStr = '';
    for (var i = 0; i < uint8arr.length; i++) {
        var hex = (uint8arr[i] & 0xff).toString(16);
        hex = (hex.length === 1) ? '0' + hex : hex;
        hexStr += hex;
    }

    return hexStr.toUpperCase();
}


function stringToUint8Array(str){
  var arr = [];
  for (var i = 0, j = str.length; i < j; ++i) {
    arr.push(str.charCodeAt(i));
  }

  var tmpUint8Array = new Uint8Array(arr);
  return tmpUint8Array
}

function str2arraybffer(str) {
    var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节
    var bufView = new Uint16Array(buf);
    for (var i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
    }
    return buf;
}

function printBytes(b){
    
    var hexstr = "";
    for (var i=0; i< b.length; i++)
    {
        var uByte = (b[i]>>>0)&0xff;
        var n = uByte.toString(16);
        hexstr += "0x" + ("00" + n).slice(-2)+", ";
    }

    return hexstr;
}

//字节数组转十六进制字符串,对负值填坑
// 二进制数据(包括内存地址)在计算机中一般以16进制的方式表示
function Bytes2HexString(arrBytes) {
    var str = "";
    for (var i = 0; i < arrBytes.length; i++) {
        var tmp;
        var num=arrBytes[i];
        if (num < 0) {
            //此处填坑,当byte因为符合位导致数值为负时候,需要对数据进行处理
            tmp =(255+num+1).toString(16);
        } else {
            tmp = num.toString(16);
        }
        if (tmp.length == 1) {
            tmp = "0" + tmp;
        }
        str += tmp;
    }
    return str;
}

// 会转成有符号的数字    JSON.stringify(bytes)
function HexString2Bytes(str) {
    var pos = 0;
    var len = str.length;
    if (len % 2 != 0) {
        return null;
    }
    len /= 2;
    var arrBytes = new Array();
    for (var i = 0; i < len; i++) {
        var s = str.substr(pos, 2);
        var v = parseInt(s, 16);
        // 转成有符号的 10进制
        if (v > 127) { v = v - 256 }
        // end
        arrBytes.push(v);
        pos += 2;
    }
    return arrBytes;
}

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;
}

function getParamType(obj) {
    return obj == null ? String(obj) : Object.prototype.toString.call(obj).replace(/\[object\s+(\w+)\]/i, "$1") || "object";
}

打印class

function printClass(c){
    var str = "-------------------------------\n";
    str += "|" + JSON.stringify(c) + "\n";
    var fields = c.getClass().getFields();
    for(var index in fields){
        var field = fields[index];
        var fieldName = "";
        var value = "";
        try{
            fieldName = field.getName();
            value = field.get(c);
        }catch(e){

        }
        if(fieldName == ""){
            continue;
        }
        str += "|" + fieldName + ":" + printValue(value) + "\n";
    }
    str += "------------------------------\n\n\n";
    return str;
}

function printValue(value){
    try{
        var newValue = Java.cast(value, Java.use("java.lang.Object"))
        switch(newValue.getClass().getName()){
            case "[B":
                return printBytes(value)
        }
        return value;
    }catch(e){
        return value;
    }
}

function printBytes(result){
    try{
        var ByteArrayOutputStreamClass = Java.use("java.io.ByteArrayOutputStream");
        var out = ByteArrayOutputStreamClass.$new()
        var ObjectOutputStreamClass = Java.use("java.io.ObjectOutputStream");
        var sOut = ObjectOutputStreamClass.$new(out);
        sOut.writeObject(result);
        sOut.flush();
        var bytes = out.toByteArray();
        var argsArray = [];
        for(var i = 0; i < bytes.length; i++) {
            argsArray.push(bytes[i]);
        }
        return "["+argsArray.join(",")+"]";
    }catch(e){
        console.log(e);
        return result;
    }
}

本文由博客群发一文多发等运营工具平台 OpenWrite 发布

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • C语言相关面试题 1.static有什么用途? 答案:在C语言中,static主要定义全局静态变量,定义局部静态变...
    ios南方阅读 6,769评论 1 18
  • 第一阶段java基础复习 1.软件开发基础 1.1开发软件的目的 提高人个计算机之间的交互方式 1.2软件 软件=...
    allencaicai阅读 476评论 0 0
  • Android 复习指南 必读: 知识结构: 覆盖的知识点:Android Java Kotin ...
    糖豆萌萌哒阅读 149评论 0 0
  • 前言 相信很多同学都会有这样的感受,前三天刚刚复习的知识点,今天问的时候怎么就讲不出个所以然了呢? 本文的目的就是...
    Y__W阅读 305评论 0 0
  • 技术不止,文章有料,加 JiuXinDev 入群,Android 搬砖路上不孤单 前言 相信很多同学都会有这样的感...
    九心_阅读 31,788评论 30 289