01 静态方法和实列方法的Hook
不需要区分修饰符,也不需要区分静态和实列方法,Hook代码的写法一模一样的
var money = Java.use("com.xiaojianbang.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);
}
02函数参数和返回值的修改
var money = Java.use("com.xiaojianbang.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("xiaojianbang");`
//上述字符串"xiaojianbang"是JS的string,而被hook的Java方法返回值是Java的String
//因此,可以主动调用Java方法转成Java的String
//但是为了方便起见,通常会直接直接返回JS的string,这时frida会自动处理,代码类似如下
//return "xiaojianbang";
//Java的类型可以调用Java的方法,JS的类型可以调用JS的方法
//区分清楚何时是Java的类型,何时是JS的类型,有助于代码的编写
//frida在参数传递的处理上也类似
}
money.setFlag.implementation = function (a) {
console.log("money.setFlag param: ", a);
return this.setFlag("xiaojianbang");
}
03构造方法的hook $init
var money=Java.use("类名全路径");
money.$init.implementation=function(a,b){
return this.$init("参数1","参数2")
}
04 对象参数的构造与修改 $new
var wallet=Java.use("类名全路径");
var money=Java.use("类名全路径");
//对象修改
wallet.deposit.implementation=function(a){
return this.deposit(money.$new("1","2"));
}
//参数修改
var wallet = Java.use("com.xiaojianbang.hook.Wallet");
wallet.deposit.implementation = function (a) {
` a.setAmount(2000);`
console.log("wallet.deposit param: ", a.getInfo());
return this.deposit(a);
}
05HashMap打印
var utils = Java.use("com.xiaojianbang.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;
}
06 方法重载的Hook
var utils = Java.use("com.xiaojianbang.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);
}
07 hook方法的所有加载
var utils = Java.use("com.xiaojianbang.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);
}
}
08 主动调用
- 静态方法,直接调用
var money = Java.use("com.xiaojianbang.hook.Money");
money.setFlag("xiaojianbang");
- 实列方法,方法1为创建新对象(一般不用)\
var moneyObj = money.$new("卢布", 1000);
console.log(moneyObj.getInfo());
- 实列方法,获取已有对象(Java.choose)
Java.choose
Java.choose("类名全路径",{
onMatch: function (obj){
console.log(obj.getInfo());
},
onComplete: function (){
console.log("内存中的Money对象搜索完毕");
}
});
09 获取和修改类的字段名
- 静态字段
value
var money = Java.use("com.xiaojianbang.hook.Money");
console.log(money.flag.value);
money.flag.value = "VX: xiaojianbang8888";
console.log(money.flag.value);
- 实例字段 创建新对象(一般不用)
var moneyObj = money.$new("欧元", 2000);
console.log(moneyObj.currency.value);
moneyObj.currency.value = "xiaojianbang currency";
console.log(moneyObj.currency.value);
- 实列字段,获取已有对象(正常用)
Java.choose("com.xiaojianbang.hook.Money", {
onMatch: function (obj) {
console.log("Java.choose Money: ", obj.currency.value);
}, onComplete: function () {
}
});
// 如果字段名和方法名一样 需要加下划线前缀
` Java.choose`
Java.choose("com.xiaojianbang.hook.BankCard", {
onMatch: function (obj) {
console.log("Java.choose BankCard: ", obj._accountName.value);
}, onComplete: function () {
}
});
10 hook内部类与匿名类
$ 内部类
Java.choose("com.xiaojianbang.hook.Wallet$InnerStructure", {
onMatch: function (obj) {
console.log(
"Java.choose Wallet$InnerStructure: ", obj.bankCardsList.value
);
}, onComplete: function () {
}
});
$1 匿名类
var money$1 = Java.use("com.xiaojianbang.app.MainActivity$1");
money$1.getInfo.implementation = function () {
var result = this.getInfo();
console.log("money.getInfo result: ", result);
return result;
}
11 枚举所有已加载的类与枚举类的所有方法
1. 枚举的是已经加载的类,没有加载的类不会出现
2. 出现的类,你也不一定能够hook到,原因是类加载器的关系
`Java.enumerateLoadedClassesSync()`
console.log(Java.enumerateLoadedClassesSync().join("\n"));
var wallet = Java.use("com.xiaojianbang.hook.Wallet");
var methods = wallet.class.getDeclaredMethods();
var constructors = wallet.class.getDeclaredConstructors();
var fields = wallet.class.getDeclaredFields();
var classes = wallet.class.getDeclaredClasses();
12 hook类的所有方法
.overloads
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.xiaojianbang.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(一般不用这个)
const MyWeirdTrustManager = Java.registerClass({
name: 'com.xiaojianbang.app.MyRegisterClass',
implements: [Java.use("com.xiaojianbang.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("xiaojianbang1", 100);
myObj.test2("xiaojianbang2", 200);
myObj.limit.value = 10000;
console.log(myObj.limit.value);
14 Frida 注入dex
Java.openClassFile("/data/local/tmp/patch.dex").load();
var test = Java.use("com.xiaojianbang.myapplication.Test");
var utils = Java.use("com.xiaojianbang.hook.Utils");
utils.shufferMap.implementation = function (map) {
var result = test.print(map);
console.log(result);
return result;
}
15 hook枚举类(Java.choose)
Java.choose("com.xiaojianbang.app.Season", {
onMatch: function (obj) {
console.log(obj.ordinal());
}, onComplete: function () {
}
})
console.log(Java.use("com.xiaojianbang.app.Season").values());
16 Frida写文件
var ios = new File("/sdcard/xiaojianbang.txt", "w");
ios.write("xiaojianbang is very good!!!\n");
ios.flush();
ios.close();
17 Java.cast
向上转型的,不能用toString直接得到结果,比如Map、List类型的打印
var utils = Java.use("com.xiaojianbang.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);
}
18 数组的构建
//Java.array("Ljava.lang.Object;", ...)
var utils = Java.use("com.xiaojianbang.hook.Utils");
//console.log(
// utils.myPrint(["xiaojianbang", "QQ:24358757", "VX:xiaojianbang8888", "公众号:非攻code"])
//);
var strarr = Java.array(
"Ljava.lang.String;",
["xiaojianbang", "QQ:24358757", "VX:xiaojianbang8888", "公众号:非攻code"]
);
console.log(utils.myPrint(strarr));
19 Object数组的构建
可变参数本质上就是数组,按数组处理即可
只需要处理基本数据类型的包装,其他的Frida会处理
var utils = Java.use("com.xiaojianbang.hook.Utils");
var bankCard = Java.use("com.xiaojianbang.hook.BankCard");
var bankCardObj = bankCard.$new("xiaojianbang", "123456789", "CBDA", 1, "15900000000");
var integer = Java.use("java.lang.Integer");
var boolean = Java.use("java.lang.Boolean");
//var objarr = Java.array(
// "Ljava.lang.Object;",
// ["xiaojianbang", integer.$new(30), boolean.$new(true), bankCardObj]
//);
console.log(
utils.myPrint(["xiaojianbang", integer.$new(30), boolean.$new(true), bankCardObj])
);
20 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.xiaojianbang.hook.BankCard");
var bankCardObj = bankCard.$new("xiaojianbang", "123456789", "CBDA", 1, "15900000000");
arrayList.add("xiaojianbang");
arrayList.add(integer.$new(30));
arrayList.add(boolean.$new(true));
arrayList.add(bankCardObj);
var utils = Java.use("com.xiaojianbang.hook.Utils");
console.log(utils.myPrint(arrayList));
21 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.xiaojianbang.app.Dynamic");
console.log("dynamic: ", dynamic);
//console.log(dynamic.$new().sayHello());
dynamic.sayHello.implementation = function () {
console.log("hook dynamic.sayHello is run!");
return "xiaojianbang";
}
} catch (e) {
console.log(loader);
}
},
onComplete: function () {}
});
22 让hook只在指定函数内生效
var mainActivity = Java.use("com.xiaojianbang.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;
};