03 Frida相关API详解

253

1. 静态方法和实例方法的hook

//不需要区分修饰符,也不需要区分静态和实例方法,hook代码的写法都是一样的
//得到Money类对象
var money = Java.use("com.andy.hook.Money");
//hook实例方法
money.getInfo.implementation = function () {
    var result = this.getInfo();
    console.log("money.getInfo result: ", result)
    return result;
}
//hook静态方法
money.setFlag.implementation = function (a) {
    console.log("money.setFlag param: ", a);
    return this.setFlag(a);
}

2. 函数参数和返回值的修改


var money = Java.use("com.andy.hook.Money");
var str = Java.use("java.lang.String");
money.getInfo.implementation = function () {
    var result = this.getInfo();
    console.log("money.getInfo result: ", result);
    return str.$new("andy");
    //上述字符串"andy"是JS的string,而被hook的Java方法返回值是Java的String
    //因此,可以主动调用Java方法转成Java的String
    //但是为了方便起见,通常会直接直接返回JS的string,这时frida会自动处理,代码类似如下
    //return "andy";
    //Java的类型可以调用Java的方法,JS的类型可以调用JS的方法
    //区分清楚何时是Java的类型,何时是JS的类型,有助于代码的编写
    //frida在参数传递的处理上也类似
}
money.setFlag.implementation = function (a) {
    console.log("money.setFlag param: ", a);
    return this.setFlag("andy");
}

3. 构造方法的hook $init

var money = Java.use("com.andy.hook.Money");
money.$init.implementation = function (a, b) {
    console.log("money.$init param: ", a, b);
    return this.$init("美元", 200);
}

4. 对象参数的构造与修改 $new

var wallet = Java.use("com.andy.hook.Wallet");
var money = Java.use("com.andy.hook.Money");
wallet.deposit.implementation = function (a) {
    console.log("wallet.deposit param: ", a.getInfo());
    return this.deposit(money.$new("美元", 200));
}

var wallet = Java.use("com.andy.hook.Wallet");
wallet.deposit.implementation = function (a) {
    a.setAmount(2000);
    console.log("wallet.deposit param: ", a.getInfo());
    return this.deposit(a);
}

5. HashMap的打印


var utils = Java.use("com.andy.hook.Utils");
var stringBuilder = Java.use("java.lang.StringBuilder");
utils.shufferMap.implementation = function (a) {
    var key = a.keySet();
    var it = key.iterator();
    var result = stringBuilder.$new();
    while(it.hasNext()){
        var keystr = it.next();
        var valuestr = a.get(keystr);
        result.append(valuestr);
    }
    console.log("utils.shufferMap param: ", result.toString());
    var result = this.shufferMap(a);
    console.log("utils.shufferMap result: ", result);
    return result;
}

6. 重载方法的hook

var utils = Java.use("com.andy.hook.Utils");
utils.getCalc.overload('int', 'int').implementation = function (a, b) {
    console.log("utils.getCalc param: ", a, b);
    return this.getCalc(a, b);
}
utils.getCalc.overload('int', 'int', 'int').implementation = function (a, b, c) {
    console.log("utils.getCalc param: ", a, b, c);
    return this.getCalc(a, b, c);
}
utils.getCalc.overload('int', 'int', 'int', 'int').implementation = function (a, b, c, d) {
    console.log("utils.getCalc param: ", a, b, c, d);
    return this.getCalc(a, b, c, d);
}

7. hook方法的所有重载

var utils = Java.use("com.andy.hook.Utils");
var overloadsArr = utils.getCalc.overloads;
for (var i = 0; i < overloadsArr.length; i++) {
    overloadsArr[i].implementation = function () {
        showStacks();
        var params = "";
        for (var j = 0; j < arguments.length; j++) {
            params += arguments[j] + " ";
        }
        console.log("utils.getCalc is called! params is: ", params);
        // if(arguments.length == 2){
        //     return this.getCalc(arguments[0], arguments[1]);
        // }else if(arguments.length == 3){
        //     return this.getCalc(arguments[0], arguments[1], arguments[2]);
        // }else if(arguments.length == 4){
        //     return this.getCalc(arguments[0], arguments[1], arguments[2], arguments[3]);
        // }
        console.log(this);
        return this.getCalc.apply(this, arguments);
    }
}

8. 主动调用

// a) 静态方法
var money = Java.use("com.andy.hook.Money");
money.setFlag("andy");
// b) 实例方法 创建新对象
var moneyObj = money.$new("卢布", 1000);
console.log(moneyObj.getInfo());
// c) 实例方法 获取已有对象(Java.choose)
Java.choose("com.andy.hook.Money", {
    onMatch: function (obj){
        console.log(obj.getInfo());
    },
    onComplete: function (){
        console.log("内存中的Money对象搜索完毕");
    }
});

// android Context的获取
var current_application = Java.use('android.app.ActivityThread').currentApplication();
var context = current_application.getApplicationContext();


9. 获取和修改类的字段

// a) 静态字段
var money = Java.use("com.andy.hook.Money");
console.log(money.flag.value);
money.flag.value = "VX: andy8888";
console.log(money.flag.value);
// b) 实例字段 创建新对象
var moneyObj = money.$new("欧元", 2000);
console.log(moneyObj.currency.value);
moneyObj.currency.value = "andy currency";
console.log(moneyObj.currency.value);
// c) 实例字段(获取已有对象)
Java.choose("com.andy.hook.Money", {
    onMatch: function (obj) {
        console.log("Java.choose Money: ", obj.currency.value);
    }, onComplete: function () {

    }
});
// 如果字段名和方法名一样 需要加下划线前缀
Java.choose("com.andy.hook.BankCard", {
    onMatch: function (obj) {
        console.log("Java.choose BankCard: ", obj._accountName.value);
    }, onComplete: function () {

    }
});

10. Hook内部类与匿名类

Java.choose("com.andy.hook.Wallet$InnerStructure", {
    onMatch: function (obj) {
        console.log(
            "Java.choose Wallet$InnerStructure: ", obj.bankCardsList.value
        );
    },
    onComplete: function () {

    }
});
var money$1 = Java.use("com.andy.app.MainActivity$1");
money$1.getInfo.implementation = function () {
    var result = this.getInfo();
    console.log("money.getInfo result: ", result);
    return result;
}

11. 枚举所有已加载的类与枚举类的所有方法


// 1. 枚举的是已经加载的类,没有加载的类不会出现
// 2. 出现的类,你也不一定能够hook到,原因是类加载器的关系
//console.log(Java.enumerateLoadedClassesSync().join("\n"));
var wallet = Java.use("com.andy.hook.Wallet");
// 。getDeclaredMethods()返回该类本身自己声明的包括公共、保护、默认(包)访问和私有方法,但并不包括超类中的方法
var methods = wallet.class.getDeclaredMethods();

// 获取类的构造方法
var constructors = wallet.class.getDeclaredConstructors();

// getDeclaredFields()返回Class中所有的字段,包括私有字段
var fields = wallet.class.getDeclaredFields();

// 返回反映对象定义的私有,受保护,公共和默认值的Class对象数组,但不包括子类或接口
var classes = wallet.class.getDeclaredClasses();

for (let i = 0; i < methods.length; i++) {
    console.log(methods[i].getName());
}
console.log("============================");
for (let i = 0; i < constructors.length; i++) {
    console.log(constructors[i].getName());
}
console.log("============================");
for (let i = 0; i < fields.length; i++) {
    console.log(fields[i].getName());
}
console.log("============================");
for (let i = 0; i < classes.length; i++) {
    console.log(classes[i].getName());
    //classes[i] 这里得到的已经是类的字节码,不需要再.calss
    var Wallet$InnerStructure = classes[i].getDeclaredFields();
    for (let j = 0; j < Wallet$InnerStructure.length; j++) {
        console.log(Wallet$InnerStructure[j].getName());
    }
}

12. hook类的所有方法

function hookFunc(methodName) {
    console.log(methodName);
    var overloadsArr = utils[methodName].overloads;
    for (var j = 0; j < overloadsArr.length; j++) {
        overloadsArr[j].implementation = function () {
            var params = "";
            for (var k = 0; k < arguments.length; k++) {
                params += arguments[k] + " ";
            }
            console.log("utils." + methodName + " is called! params is: ", params);
            return this[methodName].apply(this, arguments);
        }
    }
}

var utils = Java.use("com.andy.hook.Utils");
var methods = utils.class.getDeclaredMethods();
for (var i = 0; i < methods.length; i++) {
    var methodName = methods[i].getName();
    hookFunc(methodName);
}

13. Java.registerClass

frida的官方JavaScriptAPI frida.re/docs/javasc…

const MyWeirdTrustManager = Java.registerClass({
    name: 'com.andy.app.MyRegisterClass',
    implements: [Java.use("com.andy.app.TestRegisterClass")],
    fields: {
        description: 'java.lang.String',
        limit: 'int',
    },
    methods: {
        $init() {
            console.log('Constructor called');
        },
        test1: [{
            returnType: 'void',
            argumentTypes: [],
            implementation() {
                console.log('test1 called');
            }
        }, {
            returnType: 'void',
            argumentTypes: ['java.lang.String', 'int'],
            implementation(str, num) {
                console.log('test1(str, num) called', str, num);
            }
        }],
        test2(str, num) {
            console.log('test2(str, num) called', str, num);
            return null;
        },
    }
});
var myObj = MyWeirdTrustManager.$new();
myObj.test1();
myObj.test1("andy1", 100);
myObj.test2("andy2", 200);
myObj.limit.value = 10000;
console.log(myObj.limit.value);

19. Frida注入dex

Java.openClassFile("/data/local/tmp/patch.dex").load();
var test = Java.use("com.andy.myapplication.Test");
var utils = Java.use("com.andy.hook.Utils");
utils.shufferMap.implementation = function (map) {
    var result = test.print(map);
    console.log(result);
    return result;
}

20. hook枚举类(Java.choose)

Java.choose("com.andy.app.Season", {
    onMatch: function (obj) {
        console.log(obj.ordinal());
    }, onComplete: function () {

    }
})
console.log(Java.use("com.andy.app.Season").values());

21. Frida写文件

```js

var ios = new File("/sdcard/andy.txt", "w"); ios.write("andy is very good!!!\n"); ios.flush(); ios.close();


### 22. Java.cast
```js
向上转型的,不能用toString直接得到结果,比如Map、List类型的打印
var utils = Java.use("com.andy.hook.Utils");
utils.shufferMap2.implementation = function (map) {
    console.log("map: ", map);
    var result = Java.cast(map, Java.use("java.util.HashMap"));
    console.log("map: ", result);
    return this.shufferMap2(result);
}

23. 数组的构建

//Java.array("Ljava.lang.Object;", ...)
var utils = Java.use("com.andy.hook.Utils");
//console.log(
// utils.myPrint(["andy", "QQ:24358757", "VX:andy8888", "公众号:非攻code"])
//);
var strarr = Java.array(
   "Ljava.lang.String;", 
   ["andy", "QQ:24358757", "VX:andy8888", "公众号:非攻code"]
);
console.log(utils.myPrint(strarr));

24. Object数组的构建

//Java.array("Ljava.lang.Object;", ...)
var utils = Java.use("com.andy.hook.Utils");
//console.log(
// utils.myPrint(["andy", "QQ:24358757", "VX:andy8888", "公众号:非攻code"])
//);
var strarr = Java.array(
   "Ljava.lang.String;", 
   ["andy", "1065123672", "VX:xxxxxxx8888", "公众号:简爱code"]
);
console.log(utils.myPrint(strarr));

25. ArrayList的主动调用

var arrayList = Java.use("java.util.ArrayList").$new();
var integer = Java.use("java.lang.Integer");
var boolean = Java.use("java.lang.Boolean");
var bankCard = Java.use("com.andy.hook.BankCard");
var bankCardObj = bankCard.$new("andy", "123456789", "CBDA", 1, "15900000000");
arrayList.add("andy");
arrayList.add(integer.$new(30));
arrayList.add(boolean.$new(true));
arrayList.add(bankCardObj);
var utils = Java.use("com.andy.hook.Utils");
console.log(utils.myPrint(arrayList));

26. hook动态加载的dex(Java.enumerateClassLoaders)

// Java.enumerateLoadedClassesSync()枚举已加载类的结果中有,但是hook报错找不到类,可以尝试枚举ClassLoader,切换ClassLoader来hook
// 可以查看加载的dex所在路径
Java.enumerateClassLoaders({
    onMatch: function (loader) {
        try {
            Java.classFactory.loader = loader;
            var dynamic = Java.use("com.andy.app.Dynamic");
            console.log("dynamic: ", dynamic);
            //console.log(dynamic.$new().sayHello());
            dynamic.sayHello.implementation = function () {
                console.log("hook dynamic.sayHello is run!");
                return "andy";
            }
        } catch (e) {
            console.log(loader);
        }
    },
    onComplete: function () {}
});

27. 让hook只在指定函数内生效

var mainActivity = Java.use("com.andy.app.MainActivity");
var stringBuilder = Java.use('java.lang.StringBuilder');
mainActivity.generateAESKey.implementation = function () {
    console.log("mainActivity.generateAESKey is called!");
    stringBuilder.toString.implementation = function () {
        var result = this.toString();
        console.log(result);
        return result;
    };
    var result = this.generateAESKey.apply(this, arguments);
    stringBuilder.toString.implementation = null;  //取消hook
    return result;
};

28 hook定位接口的实现类

var classes = Java.enumerateLoadedClassesSync();
    for (const index in classes) {
        let className = classes[index];
        if(className.indexOf("com.andy") === -1) continue;
        try {
            let clazz = Java.use(className);
            let resultArr = clazz.class.getInterfaces();
            console.log("resultArr: ", resultArr);
            if(resultArr.length === 0) continue;
            for (let i = 0; i < resultArr.length; i++) {
                if(resultArr[i].toString().indexOf("com.andy.app.TestRegisterClass") !== -1){
                    console.log(className, resultArr);
                }
            }
        }catch (e) {console.log("Didn't find class: " + className);}
    }

29 hook定位抽象类的实现类

var classes = Java.enumerateLoadedClassesSync();
for (const index in classes) {
    let className = classes[index];
    if(className.indexOf("com.andy") === -1) continue;
    try {
        let clazz = Java.use(className);
        let resultClass = clazz.class.getSuperclass();
        console.log("resultClass: ", className, resultClass);
        if(resultClass == null) continue;
        if(resultClass.toString().indexOf("com.andy.app.TestAbstract") !== -1){
            console.log(className, resultClass);
        }
    } catch (e) {}
}