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) {}
}