hook方法的所有重载

Java.perform(function(){

function showStacks(){
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}

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);
console.log(this);
return this.getCalc.apply(this,arguments);
}
}
});

主动调用

静态方法

var money = Java.use("com.xiaojianbang.hook.Money");
money.setFlag("xiaojianbang");

实例方法 创建新对象

var moneyObj = money.$new("卢布", 1000);
console.log(moneyObj.getInfo());

实例方法 获取已有对象(Java.choose)

Java.choose("com.xiaojianbang.hook.Money",{
onMatch: function(obj){
console.log(obj.getInfo());
},
onComplete: function(){
console.log("内存中的Moeny对象搜索完毕");
}
});

获取和修改类的字段

静态字段

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("com.xiaojianbang.hook.BankCard",{
onMatch: function(obj){
console.log("Java.choose BankCard: ",obj._accountName.value);
},
onComplete: function(){}
});

Hook内部类与匿名类

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

}
});

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

枚举所有已加载的类

// 1. 枚举的是已经加载的类,没加载的类不会出现
// 2. 出现的类,也不一定能hook到,原因是类加载器不同
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();

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());
}
console.log("======================================");
for(let i = 0; i < classes.length; i++) {
console.log(classes[i].getName());
//classes[i] 这里得到的已经是类的字节码,不需要再.class
var Wallet$InnerStructure = classes[i].getDeclaredFields();
for(let j = 0; j < Wallet$InnerStructure.length; j++){
console.log(Wallet$InnerStructure[j].getName());
}
}

hook类的所有方法

Java.perform(function(){

function hookFunc(methodName){
console.log(methodName);
var overloadsArr = utils[methodName].overloads;
for(var i=0;i<overloadsArr.length;i++){
overloadsArr[i].implementation = function () {
var params = "";
for(var k = 0; k < arguments.length; k++){
params += arguments[k] + " ";
}
console.log(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);
}
});

Java.registerClass

Java.perform(function(){
const MyWeirdTrustManager = Java.registerClass({
name: 'com.xiaojianbang.app.MyWeirdTrustManager',
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('test 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);
});

frida注入dex

package com.example.myapplication;

import android.util.Log;

public class Test{
public static void print(){
Log.d("xiaojianbang","这自己注入的代码");
}
}

编译过后推送到手机

adb push xxx.dex /data/local/tmp

注入dex

Java.perform(function(){
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;
}
});

hook枚举类(Java.choose)

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

frida写文件

Java.perform(function(){
var ios = new File("/data/data/com.xiaojianbang.app/xiaojianbang.txt","a+");
ios.write("xiaojianbang is very good!!!\n");
ios.flush();
ios.close();
});

Java.cast

//向上转型的,不能用toStirng直接得到结果,比如Map、List类型的打印
Java.perform(function(){
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);
}
});

数组的构建

Java.perform(function(){
var Utils = Java.use("com.xiaojianbang.hook.Utils");
var strarr = Java.array(
"Ljava.lang.String;",
["xiaojianbang","QQ: 24358757","VX: xiaojianbang8888","公众号: 非code"]
);
var retval = Utils.myPrint(strarr);
console.log(retval);
});

可变参数的构造

// Object数组的构建
// 可变参数本质上就是数组, 按数组处理即可
// 只需要处理基本数据类型的包装,其他的Frida会处理
Java.perform(function(){
var utils = Java.use("com.xiaojianbang.hook.Utils");
var money = Java.use("com.xiaojianbang.hook.Money").$new("xiaojianbang", 20000);
var Bool = Java.use("java.lang.Boolean");
var integer = Java.use("java.lang.Integer");
var retval2 = utils.myPrint(["xiaojianbang", integer.$new(100),Bool.$new(true),money])
console.log(retval2);
});

ArrayList的主动调用

Java.perform(function(){
var Bool = Java.use("java.lang.Boolean");
var integer = Java.use("java.lang.Integer");
var money = Java.use("com.xiaojianbang.hook.Money").$new("xiaojianbang", 20000);
var arrayList = Java.use("java.util.ArrayList").$new();
var Utils = Java.use("com.xiaojianbang.hook.Utils");
arrayList.add("xiaojianbang");
arrayList.add(integer.$new(100));
arrayList.add(Bool.$new(false));
arrayList.add(money);
console.log("arrayList: ",arrayList.toString());
var retval3 = Utils.myPrint(arrayList);
console.log(retval3);
});

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

//Java.enumerateLoadedClassSync()枚举已加载的类的结果中有,但是hook报错找不到类,可以切换ClassLoader来hook
Java.perform(function(){
Java.enumerateClassLoaders({
onMatch: function (loader){
try{
Java.classFactory.loader = loader
var dynamic = Java.use("com.xiaojianbang.app.Dynamic");
console.log("dynamic: ", dynamic);
dynamic.sayHello.implementation = function (){
console.log("hook dynamic.sayHello is run!");
return "xiaojianbang";
}
}catch (e){
console.log(loader);
}
},
onComplete: function (){

}
});
});

让hook只在指定的函数内生效

Java.perform(function(){
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;
}
});

hook定位接口的实现类

Java.perform(function(){
var classes = Java.enumerateLoadedClassesSync();
for (const index in classes) {
let className = classes[index];
if(className.indexOf("com.xiaojianbang") === -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.xiaojianbang.app.TestRegisterClass") !== -1){
console.log(className, resultArr);
}
}
}catch (e) {console.log("Didn't find class: " + className);}
}
});

hook定位抽象类的实现

Java.perform(function(){
var classes = Java.enumerateLoadedClassesSync();
for (const index in classes) {
let className = classes[index];
if(className.indexOf("com.xiaojianbang") === -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.xiaojianbang.app.TestAbstract") !== -1){
console.log(className, resultClass);
}
} catch (e) {}
}
});

frida.exe的使用

frida --help 查看帮助
frida --version 查看版本
frida -U -F 直接注入当前app
frida -U -n com.xiaojianbang.app 注入当前app
frida -U -p 9791 通过PID注入,-p可以省略

frida连接多个设备

netstat -nltp 查看端口
./fsarm64 -l 0.0.0.0:8000 改变端口
ip address 查看ip地址
frida -H 10.194.0.131:8000 -F 远程连接

脱离PC使用frida

./fiarm64 -n com.xiaojianbang.app -s test2.js -e //e表示eternal

objection

objection的安装

pip install objection==1.11.0

objectioni的使用

注入进程,如果objection没有找到进程,会议spwan方式启动进程

objection --help
objection -g 进程名 explore

C:\Users\17704.objection输入文件的路径

列出所有已加载的类

android hooking list classes

在所有已加载的类中搜索包含特定关键字的类

android hooking search classes 关键字

列出类的所有方法

android hooking list class_methods 路径.类名

hook类的所有方法(不包括构造方法)

android hooking watch class 路径.类名

hook类的构造方法

android hooking watch class_method 路径.类名.$init

默认是hook方法的所有重载

android hooking watch class_method 路径.类名.方法名

hook方法的参数、返回值和调用栈

android hooking watch class_method 路径.类名.方法名 --dump-args --dump-return --dump-backtrace

hook单个重载函数,需要指定参数类型,多个参数用逗号分隔

android hooking watch class_method 路径.类名.方法名 "参数类型"

查看hook了多少个类

jobs list

取消hook

jobs kill jobId

指定ip和端口连接

objection -N -h ip -p port -g 进程名 explore

启动前就hook

objection -N -h <ip> -p <port> -g 进程名 explore --startup-command "android hooking watch class 路径.类名" 

启动前就hook打印参数、返回值、函数调用栈

objection -N -h ip -p port -g 进程名 explore --startup-command "android hooking watch class_method 路径.类名.方法名"

启动前就hook打印参数、返回子、函数调用栈

objection -N -h ip -p port -g 进程名 explore --startup-command "android hooking watch class_method 路径.类名.方法名 --dump-args --dump-return --dump-backtrace"

hook单个重载函数,需要指定类型参数,多个参数用逗号分隔

android hooking watch class_method 路径.类名.方法名 "参数类型"

关闭ssl校验

android sslpinning disable

关闭root检测

android root disable

查看当前app的activity

android hooking list activities

尝试跳转到对应的activity

android intent launch_activity

Wallbreaker

objection的插件加载

插件路径后面的名字自己取

plugin load 插件路径 Wallbreaker 

搜索类

plubin Wallbreaker classsearch <pattern>

搜索对象

plugin Wallbreaker objectsearch <classname>

classdump输出类结构,若加了fullname参数,打印数据中的类名会带完整包名

plugin Wallbreaker classdump <classname>

objectdump在classdump的基础上,输出指定对象中的每个字段的数据

plugin Wallbreaker objectdump <handle> 

脱离PC使用frida

查看手机架构

adb shell getprop ro.product.cpu.abi