fridahookjava Frida 启动 frida-server 自定义端口 Frida rpc 远程调用 Hook 普通方法 Hook 重载方法 Hook 构造方法 Hook 对象 Hook 动静态成员属性 Hook 内部类 Hook 匿名类 Hook 类的所有方法 Hook 类的所有方法及重载 Hook 动态加载的 dex Hook 主动构造数组 Hook cast 强制类型转换 Hook 打印类实现的接口 Hook enum 枚举 Hook 获取 context Hook 主动调用构造方法 Hook 主动调用静态方法 Hook 主动调用动态方法 Hook frida 和 python 交互 Hook 打印 char Hook 打印 char 数组 Hook 打印和修改 HashMap Hook 打印 byte 数组 Hook 打印调用栈 Hook gson 打印 Hook 打印 non-ascii 和特殊字符 简易 wallbreaker 内存打印 hook frida 实现 runn

fridahookjava
Frida 启动
frida-server 自定义端口
Frida rpc 远程调用
Hook 普通方法
Hook 重载方法
Hook 构造方法
Hook 对象
Hook 动静态成员属性
Hook 内部类
Hook 匿名类
Hook 类的所有方法
Hook 类的所有方法及重载
Hook 动态加载的 dex
Hook 主动构造数组
Hook cast 强制类型转换
Hook 打印类实现的接口
Hook enum 枚举
Hook 获取 context
Hook 主动调用构造方法
Hook 主动调用静态方法
Hook 主动调用动态方法
Hook frida 和 python 交互
Hook 打印 char
Hook 打印 char 数组
Hook 打印和修改 HashMap
Hook 打印 byte 数组
Hook 打印调用栈
Hook gson 打印
Hook 打印 non-ascii 和特殊字符
简易 wallbreaker 内存打印
hook frida 实现 runn

attach 启动

直接附加到指定包名的应用中

BASH
frida -U com.kevin.android -l hook.js --no-pause

直接附加到当前应用中

BASH
frida -UF -l hook.js --no-pause
import sys
import time
import frida

def on_message(message,data):
    print("message",message)
    print("data",data)

device = frida.get_usb_device()
session = device.attach("com.kevin.demo1")

with open("./demo1.js","r") as f:
    script = session.create_script(f.read())

script.on("message",on_message)
script.load()
sys.stdin.read()

spawn 启动

BASH
frida -U -f com.kevin.android -l demo1.js --no-pause
import sys
import time
import frida

def on_message(message,data):
    print("message",message)
    print("data",data)

device = frida.get_usb_device()
pid = device.spawn(["com.kevin.demo1"])
device.resume(pid)
session = device.attach(pid)

with open("./rpc_demo.js",'r') as f:
    script = session.create_script(f.read())

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

sys.stdin.read()

frida-server 自定义端口

frida server

更改 frida server 默认端口: 27042 并开启远程连接

BASH
adb shell
su -
cd /data/local/tmp

# 输入 wifiadb 对应的 ip 和自定义端口
./frida-server -l 192.168.0.1:6666

# 也可以使用默认端口启动
./frida-server -l 192.168.0.1

frida

frida 远程连接自定义端口

BASH
# 连接指定 6666 端口
frida -H 192.168.0.1:6666 com.demo1.app -l demo1.js

# 默认使用端口 27042
frida -H 192.168.0.1 -l demo1.js

python

PYTHON
# -*- coding: UTF-8 -*-

import frida, sys

jsCode = """
console.log("test");
"""

def message(message, data):
    if message['type'] == 'send':
        print(f"[*] {message['payload']}")
		else:
				print(message)
# ./fs120800 -l "0.0.0.0:6666"
# adb wifi 10.0.0.23
process = frida.get_device_manager().add_remote_device('127.0.0.1:6666').attach('com.kevin.app')
script = process.create_script(jsCode)
script.on("message",message)
script.load()
input()

Frida rpc 远程调用

python

PYTHON
import frida
import json
from flask import Flask, jsonify, request

def message(message, data):
	if message['type'] == 'send':
		print(f"[*] {message['payload']}")
	else:
		print(message)

# ./fs120800 -l "0.0.0.0:6666"
# adb wifi 10.0.0.123
# 远程 frida-server 路径 adb wifi 的 ip : frida-server 启动的端口
session = frida.get_device_manager().add_remote_device('10.0.0.123:6666').attach('com.example.demoso1')
with open("/Users/zhangyang/codes/fridaProject/rpcDemo/hook.js") as f:
    jsCode = f.read()

# print("加载代码", jsCode)
script = session.create_script(jsCode)
script.on("message",message)
script.load()

# print("加密","1213")
# encodeResult = script.exports.invokemethod01("123")
# decodeResult = script.exports.invokemethod02(encodeResult)
# print(decodeResult)

app = Flask(__name__)

@app.route('/encrypt', methods=['POST'])#data解密
def decrypt_class():
    data = request.get_data()
    json_data = json.loads(data.decode("utf-8"))
    postdata = json_data.get("data")
    res = script.exports.invokemethod01(postdata)
    return res
 
 
@app.route('/decrypt', methods=['POST'])#url加密
def encrypt_class():
    data = request.get_data()
    json_data = json.loads(data.decode("utf-8"))
    postdata = json_data.get("data")
    print(postdata)
    res = script.exports.invokemethod02(postdata)
    return res

if __name__ == "__main__":
	app.run()

js

JSX
///<reference path='/Users/zhangyang/node_modules/@types/frida-gum/index.d.ts'/>

// 先 hook 方法 method01
// function hookmethod1(){
//     Java.perform(function(){
//         var targetClass = Java.use("com.example.demoso1.MainActivity");
//         targetClass.method01.implementation = function(str){
//             console.log("str is ", str);
//             var result = this.method01(str);
//             console.log("result is ", result);
//             return result;
//         }
//     })
// };

// 主动调用
function fridamethod01(inputStr){
    var result = null;
    Java.perform(function(){
        var targetClass = Java.use("com.example.demoso1.MainActivity");
        result = targetClass.method01(inputStr);
    });
    return result;
}

function fridamethod02(inputStr){
    var result = null;
    // public native String method02(String str);
    Java.perform(function(){
        Java.choose("com.example.demoso1.MainActivity",{
            onMatch: function(ins){
                result = ins.method02(inputStr);
            },
            onComplete: function(){}
        })
    });
    return result;
}

// 优先测试 js 中的主动调用
// function main(){
//     console.log("你好 -> 结果为:", fridamethod01("你好"));
//     console.log("27cae29a0913f6791705ca10be31a3e0 -> 结果为", fridamethod02("27cae29a0913f6791705ca10be31a3e0"))
    
// }
// setImmediate(main);

// 基于主动调用设置 rpc
rpc.exports = {
    invokemethod01: fridamethod01,
    invokemethod02: fridamethod02,
}

压力测试

tmp.json

JSON{"data": "62feb9a98a01945ab06c0dd7823adc57"}

命令

BASHsiege -c30 -r1 "<http://127.0.0.1:5000/encrypt> POST < tmp.json"

nps 进行内网穿透

  1. nps server 启动

    mac: sudo nps start

  2. 新建客户端

    fridahookjava
Frida 启动
frida-server 自定义端口
Frida rpc 远程调用
Hook 普通方法
Hook 重载方法
Hook 构造方法
Hook 对象
Hook 动静态成员属性
Hook 内部类
Hook 匿名类
Hook 类的所有方法
Hook 类的所有方法及重载
Hook 动态加载的 dex
Hook 主动构造数组
Hook cast 强制类型转换
Hook 打印类实现的接口
Hook enum 枚举
Hook 获取 context
Hook 主动调用构造方法
Hook 主动调用静态方法
Hook 主动调用动态方法
Hook frida 和 python 交互
Hook 打印 char
Hook 打印 char 数组
Hook 打印和修改 HashMap
Hook 打印 byte 数组
Hook 打印调用栈
Hook gson 打印
Hook 打印 non-ascii 和特殊字符
简易 wallbreaker 内存打印
hook frida 实现 runnable
Hook 监控控件 onClick
Hook startActivity
Hook frida 绕过 root 检测
Hook frida 强制在主线程运行
Hook frida 指定方法中过滤打印
Hook 禁止 app 退出
Hook 修改设备参数
Hook 打印请求调用栈
Hook UI thread 注入
常用打印转换

    安卓手机连接客户端 ./npc -server=10.0.0.124:8024 -vkey=hm40rtjpf2j3c1up -type=tcp

  3. 给客户端添加和 frida server 的端口映射

    安卓手机启动 frida-server: ./fs12800 -l 0.0.0.0:6666

    fridahookjava
Frida 启动
frida-server 自定义端口
Frida rpc 远程调用
Hook 普通方法
Hook 重载方法
Hook 构造方法
Hook 对象
Hook 动静态成员属性
Hook 内部类
Hook 匿名类
Hook 类的所有方法
Hook 类的所有方法及重载
Hook 动态加载的 dex
Hook 主动构造数组
Hook cast 强制类型转换
Hook 打印类实现的接口
Hook enum 枚举
Hook 获取 context
Hook 主动调用构造方法
Hook 主动调用静态方法
Hook 主动调用动态方法
Hook frida 和 python 交互
Hook 打印 char
Hook 打印 char 数组
Hook 打印和修改 HashMap
Hook 打印 byte 数组
Hook 打印调用栈
Hook gson 打印
Hook 打印 non-ascii 和特殊字符
简易 wallbreaker 内存打印
hook frida 实现 runnable
Hook 监控控件 onClick
Hook startActivity
Hook frida 绕过 root 检测
Hook frida 强制在主线程运行
Hook frida 指定方法中过滤打印
Hook 禁止 app 退出
Hook 修改设备参数
Hook 打印请求调用栈
Hook UI thread 注入
常用打印转换

    将目标 frida-server 的端口映射到 56666 端口上

  4. python 脚本更改和 frida-server 的连接

    PYTHONsession = frida.get_device_manager().add_remote_device('10.0.0.124:56666').attach('com.example.demoso1')
    

    此时就可以将 frida-server 开放到公网了;

Hook 普通方法

JSfunction main(){    Java.perform(function(){        var UtilsClass = Java.use("com.kevin.app.Utils");        UtilsClass.getCalc.implementation = function (a,b){        	// 打印信息	        console.log('a:' + a + ' ' + 'b:' + b);    	    // 调用原方法获取结果        	var value = this.getCalc(a, b);	        console.log('result:',value);            // 修改返回值    	    return 123456;            }    })}setImmediate(main);

Hook 重载方法

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

Hook 构造方法

JSfunction main(){    Java.perform(function (){        // hook 构造方法 $init        var MoneyClass = Java.use("com.kevin.app.Money");        MoneyClass.$init.overload().implementation = function(){            console.log("hook Money $init");            this.$init();        }    })}setImmediate(main);

Hook 对象

JSfunction main(){    Java.perform(function(){        // hook instance        Java.choose("com.xiaojianbang.app.Money",{            onMatch : function(instance){                console.log("find it!!", instance.getInfo());                // something to do...            },                        onComplete: function(){                console.log("compelete!!!");            }        })    })}setImmediate(main);

Hook 动静态成员属性

JSfunction main(){    Java.perform(function(){        var MoneyClass = Java.use("com.xiaojianbang.app.Money");                // get static properties        // need to use .value        var ori_property = MoneyClass.flag.value;        console.log("ori_property: ", ori_property);                // change static properties         MoneyClass.flag.value = "change the value";        console.log("change to : ", MoneyClass.flag.value);                // get dynamic properties         Java.choose("com.xiaojianbang.app.Money",{            onMatch: function(instance){                instance.num.value = 50000;                // 当对象的成员属性和成员方法名重复时,成员属性前加`_`,进行区分                instance._name.value = "ouyuan";                 console.log(instance._name.value, instance.num.value, instance.flag.value);            },                        onComplete: function(){                console.log("complete!!")            }        })    })}setImmediate(main);

Hook 内部类

JSfunction 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 匿名类

JS// 接口, 抽象类, 不可以被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 类的所有方法

  • Java.enumerateLoadedClasses()
JSfunction 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!!!")            }        })    })}
  • Java.enumerateLoadedClassesSync()
JSfunction 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());            	}                           }        }    })}setImmediate(main)

Hook 类的所有方法及重载

JSfunction main(){    Java.perform(function(){        // hook md5 class in app        // 1. iterate classes        var classList = Java.enumerateLoadedClassesSync();        for (var i = 0; i < classList.length; i++){            // 筛选过滤 只遍历 MD5 下面的方法            if (classList[i].indexOf("com.xiaojianbang.app.MD5") != -1){                var className = classList[i];                console.log("class name is :", className);                // 2. get methods of the class                // 返回一个 Methods对象的数组                var methodsList = Java.use(className).class.getDeclaredMethods();                for (var k=0; k<methodsList.length; k++){                                        // console.log("method is :",methodsList[k],typeof(methodsList[k]));                                        // 3. Method object.getName() --> methodName and class[methodName] to hook method                    var methodName = methodsList[k].getName(); //                                         // console.log('methodName',methodName);                    // 4. use apply and arguments to implementation                    var hookClass = Java.use(className);                    // 5. overloads                    for (var o = 0; o< hookClass[methodName].overloads.length; o++){                        hookClass[methodName].overloads[o].implementation = function(){                            for (var a=0; a<arguments.length; a++){                                console.log('argument ',a,arguments[a]);                            }                            // return this[methodName].apply(this,arguments);                            return "fucking the md5"                        }                    }                }            }        }    })}

Hook 动态加载的 dex

JSfunction main(){    Java.perform(function(){        Java.enumerateClassLoaders({            onMatch : function(loader){                try {                    // loadClass or findClass                    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);                        // something to do;                    }                } catch (error) {                    // pass                }            },                        onComplete: function () {                console.log("complete !!! ")            }        })    })}setImmediate(main);

经常在加壳的 app 中, 没办法正确找到正常加载 app 类的 classloader, 可以使用以下代码:

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

Hook 主动构造数组

JSfunction mainArray(){    Java.perform(function(){        var myCharList = Java.array("char",['一','去','二','三','里']);        var myStringList = Java.array("java.lang.String",["一","二","三"]);        var ArrayClass = Java.use("java.util.Arrays");        console.log(ArrayClass.toString(myCharList));        console.log(ArrayClass.toString(myStringList));    })}

Hook cast 强制类型转换

JS// 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 打印类实现的接口

JSfunction 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("	", interfaceList[i].toString()); // 直接打印接口名称                        }                    }                }            }        })    })}

Hook enum 枚举

JSfunction 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 获取 context

JSfunction 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());    })}

Hook 主动调用构造方法

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

Hook 主动调用静态方法

JSfunction main_rsa(){    Java.perform(function(){        var RSA = Java.use("com.xiaojianbang.app.RSA");        var StringClass = Java.use("java.lang.String");        var base64Class = Java.use("android.util.Base64");        var myBytes = StringClass.$new("Hello World").getBytes();        var result = RSA.encrypt(myBytes);        console.log("result is :", result);        console.log("json result is: ",JSON.stringify(result));        console.log("base64 result is :", base64Class.encodeToString(result,0));        // console.log("new String is : ", StringClass.$new(result)); // 加密之后的内容有很多不可见字符, 不能直接 new String()    })}setImmediate(main_rsa);

Hook 主动调用动态方法

JS// 非静态方法的主动调用 自定义instance 并调用 非静态方法function main_getInfo(){    Java.perform(function(){        var instance = Java.use("com.xiaojianbang.app.Money").$new("日元",300000);        console.log(instance.getInfo());    })}// 遍历所有的对象并调用 需要进行过滤function main_instance_getInfo(){    Java.perform(function(){        Java.choose("com.xiaojianbang.app.Money",{            onComplete: function(){},            onMatch: function(instance){                console.log(instance.getInfo());            }        })    })}

Hook frida 和 python 交互

CODEfrida 传递参数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 sysimport timeimport base64import fridafrom loguru import loggerdef 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()

Hook 打印 char

JS// 打印char字符, 直接调用java.lang.Character toString()即可function main(){    Java.perform(function(){        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;        }    })}

Hook 打印 char 数组

JS// 1. 使用 java.util.Arrays 的 toString 方法 打印 [C // 2. 使用 js 的 JSON.stringify 打印 [Cfunction printCharArray(){    Java.perform(function(){        var ArrayClass = Java.use("java.util.Arrays");        ArrayClass.toString.overload('[C').implementation = function(charArray){            // 1. java.util.Arrays.toString()            var result = this.toString(charArray);            // 2. javascript JSON.stringify()            var result1 = JSON.stringify(charArray);            console.log('charArray, result : ', charArray, result);            console.log('charArray, result :', charArray, result1);        }    })}

Hook 打印和修改 HashMap

CODE遍历打印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));            this.show(map);                        return this.show(map);        }    })    }setImmediate(main);cast打印 HashMapfunction 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);        }    })}setImmediate(main);

toString()打印

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

Hook 打印 byte 数组

CODE方法 1function main(){    Java.perform(function(){            var StringClass = Java.use("java.lang.String");            var byteArray = StringClass.$new("Hello World").getBytes();                        // load r0gson	        // openClassFile 返回 dex对象, dex对象.load()加载dex文件内容            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));            var TargetClass = Java.use("com.xiaojianbang.app.ShufferMap");            TargetClass.show.implementation =  function(map){                console.log(gson.$new().toJson(map));                return this.show(map);            }    })}setImmediate(main);方法 2// 1. 使用 java.util.Arrays.toString() 打印 [B// 2. 使用 javascript JSON.stringify() 打印 [Bfunction printByteArray(){    Java.perform(function(){        var ArrayClass = Java.use("java.util.Arrays");        ArrayClass.toString.overload('[B').implementation = function(byteArray){			// 1. 使用 java.util.Arrays.toString() 打印 [B            var result = this.toString(byteArray);			// 2. 使用 javascript JSON.stringify() 打印 [B            var result1 = JSON.stringify(byteArray);                        console.log('byteArray,result: ', byteArray, result);            console.log('byteArray,result1 :', byteArray, result1);            return result        }    })}方法 3function printByteArray(byteArray){	Java.perform(function(){		var ByteString = Java.use("com.android.okhttp.okio.ByteString");		console.log(ByteString.of(byteArray).hex())	})}

Hook 打印调用栈

JSfunction 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 + "==============================")}

Hook gson 打印

JSfunction main(){    Java.perform(function(){            var StringClass = Java.use("java.lang.String");            var byteArray = StringClass.$new("Hello World").getBytes();                        // load r0gson	        // openClassFile 返回 dex对象, dex对象.load()加载dex文件内容            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));            var TargetClass = Java.use("com.xiaojianbang.app.ShufferMap");            TargetClass.show.implementation =  function(map){                console.log(gson.$new().toJson(map));                return this.show(map);            }    })}setImmediate(main);

Hook 打印 non-ascii 和特殊字符

一些特殊字符和不可见字符, 可以先通过编码再解码的方式进行 hook

JAVAint ֏(int x) {        return x + 100;    }

针对上面的֏, 直接用js编码, 在通过类名[js解码的方法名]进行implementation

JSJava.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 内存打印

内存漫游, 打印实例的字段和方法

JSfunction 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("	 Fields:")            for (var i in fields){                console.log("		" + fields[i].toString());            }            console.log("	 Methods:")            for (var i in methods){                console.log("		" + 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)

hook frida 实现 runnable

JSJava.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 监控控件 onClick

JSvar 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 startActivity

JSJava.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);    }})

Hook frida 绕过 root 检测

JS// $ frida -l antiroot.js -U -f com.example.app --no-pause// CHANGELOG by Pichaya Morimoto (p.morimoto@sth.sh): //  - I added extra whitelisted items to deal with the latest versions // 						of RootBeer/Cordova iRoot as of August 6, 2019//  - The original one just fucked up (kill itself) if Magisk is installed lol// Credit & Originally written by: https://codeshare.frida.re/@dzonerzy/fridantiroot/// If this isn't working in the future, check console logs, rootbeer src, or libtool-checker.soJava.perform(function() {    var RootPackages = ["com.noshufou.android.su", "com.noshufou.android.su.elite", "eu.chainfire.supersu",        "com.koushikdutta.superuser", "com.thirdparty.superuser", "com.yellowes.su", "com.koushikdutta.rommanager",        "com.koushikdutta.rommanager.license", "com.dimonvideo.luckypatcher", "com.chelpus.lackypatch",        "com.ramdroid.appquarantine", "com.ramdroid.appquarantinepro", "com.devadvance.rootcloak", "com.devadvance.rootcloakplus",        "de.robv.android.xposed.installer", "com.saurik.substrate", "com.zachspong.temprootremovejb", "com.amphoras.hidemyroot",        "com.amphoras.hidemyrootadfree", "com.formyhm.hiderootPremium", "com.formyhm.hideroot", "me.phh.superuser",        "eu.chainfire.supersu.pro", "com.kingouser.com", "com.android.vending.billing.InAppBillingService.COIN","com.topjohnwu.magisk"    ];    var RootBinaries = ["su", "busybox", "supersu", "Superuser.apk", "KingoUser.apk", "SuperSu.apk","magisk"];    var RootProperties = {        "ro.build.selinux": "1",        "ro.debuggable": "0",        "service.adb.root": "0",        "ro.secure": "1"    };    var RootPropertiesKeys = [];    for (var k in RootProperties) RootPropertiesKeys.push(k);    var PackageManager = Java.use("android.app.ApplicationPackageManager");    var Runtime = Java.use('java.lang.Runtime');    var NativeFile = Java.use('java.io.File');    var String = Java.use('java.lang.String');    var SystemProperties = Java.use('android.os.SystemProperties');    var BufferedReader = Java.use('java.io.BufferedReader');    var ProcessBuilder = Java.use('java.lang.ProcessBuilder');    var StringBuffer = Java.use('java.lang.StringBuffer');    var loaded_classes = Java.enumerateLoadedClassesSync();    send("Loaded " + loaded_classes.length + " classes!");    var useKeyInfo = false;    var useProcessManager = false;    send("loaded: " + loaded_classes.indexOf('java.lang.ProcessManager'));    if (loaded_classes.indexOf('java.lang.ProcessManager') != -1) {        try {            //useProcessManager = true;            //var ProcessManager = Java.use('java.lang.ProcessManager');        } catch (err) {            send("ProcessManager Hook failed: " + err);        }    } else {        send("ProcessManager hook not loaded");    }    var KeyInfo = null;    if (loaded_classes.indexOf('android.security.keystore.KeyInfo') != -1) {        try {            //useKeyInfo = true;            //var KeyInfo = Java.use('android.security.keystore.KeyInfo');        } catch (err) {            send("KeyInfo Hook failed: " + err);        }    } else {        send("KeyInfo hook not loaded");    }    PackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(pname, flags) {        var shouldFakePackage = (RootPackages.indexOf(pname) > -1);        if (shouldFakePackage) {            send("Bypass root check for package: " + pname);            pname = "set.package.name.to.a.fake.one.so.we.can.bypass.it";        }        return this.getPackageInfo.call(this, pname, flags);    };    NativeFile.exists.implementation = function() {        var name = NativeFile.getName.call(this);        var shouldFakeReturn = (RootBinaries.indexOf(name) > -1);        if (shouldFakeReturn) {            send("Bypass return value for binary: " + name);            return false;        } else {            return this.exists.call(this);        }    };    var exec = Runtime.exec.overload('[Ljava.lang.String;');    var exec1 = Runtime.exec.overload('java.lang.String');    var exec2 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;');    var exec3 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;');    var exec4 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File');    var exec5 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;', 'java.io.File');    exec5.implementation = function(cmd, env, dir) {        if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {            var fakeCmd = "grep";            send("Bypass " + cmd + " command");            return exec1.call(this, fakeCmd);        }        if (cmd == "su") {            var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";            send("Bypass " + cmd + " command");            return exec1.call(this, fakeCmd);        }        if (cmd == "which") {            var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";            send("Bypass which command");            return exec1.call(this, fakeCmd);        }        return exec5.call(this, cmd, env, dir);    };    exec4.implementation = function(cmdarr, env, file) {        for (var i = 0; i < cmdarr.length; i = i + 1) {            var tmp_cmd = cmdarr[i];            if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {                var fakeCmd = "grep";                send("Bypass " + cmdarr + " command");                return exec1.call(this, fakeCmd);            }            if (tmp_cmd == "su") {                var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";                send("Bypass " + cmdarr + " command");                return exec1.call(this, fakeCmd);            }        }        return exec4.call(this, cmdarr, env, file);    };    exec3.implementation = function(cmdarr, envp) {        for (var i = 0; i < cmdarr.length; i = i + 1) {            var tmp_cmd = cmdarr[i];            if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {                var fakeCmd = "grep";                send("Bypass " + cmdarr + " command");                return exec1.call(this, fakeCmd);            }            if (tmp_cmd == "su") {                var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";                send("Bypass " + cmdarr + " command");                return exec1.call(this, fakeCmd);            }        }        return exec3.call(this, cmdarr, envp);    };    exec2.implementation = function(cmd, env) {        if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {            var fakeCmd = "grep";            send("Bypass " + cmd + " command");            return exec1.call(this, fakeCmd);        }        if (cmd == "su") {            var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";            send("Bypass " + cmd + " command");            return exec1.call(this, fakeCmd);        }        return exec2.call(this, cmd, env);    };    exec.implementation = function(cmd) {        for (var i = 0; i < cmd.length; i = i + 1) {            var tmp_cmd = cmd[i];            if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {                var fakeCmd = "grep";                send("Bypass " + cmd + " command");                return exec1.call(this, fakeCmd);            }            if (tmp_cmd == "su") {                var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";                send("Bypass " + cmd + " command");                return exec1.call(this, fakeCmd);            }        }        return exec.call(this, cmd);    };    exec1.implementation = function(cmd) {        if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {            var fakeCmd = "grep";            send("Bypass " + cmd + " command");            return exec1.call(this, fakeCmd);        }        if (cmd == "su") {            var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";            send("Bypass " + cmd + " command");            return exec1.call(this, fakeCmd);        }        return exec1.call(this, cmd);    };    String.contains.implementation = function(name) {        if (name == "test-keys") {            send("Bypass test-keys check");            return false;        }        return this.contains.call(this, name);    };    var get = SystemProperties.get.overload('java.lang.String');    get.implementation = function(name) {        if (RootPropertiesKeys.indexOf(name) != -1) {            send("Bypass " + name);            return RootProperties[name];        }        return this.get.call(this, name);    };    Interceptor.attach(Module.findExportByName("libc.so", "fopen"), {        onEnter: function(args) {            var path1 = Memory.readCString(args[0]);            var path = path1.split("/");            var executable = path[path.length - 1];            var shouldFakeReturn = (RootBinaries.indexOf(executable) > -1)            if (shouldFakeReturn) {                Memory.writeUtf8String(args[0], "/ggezxxx");                send("Bypass native fopen >> "+path1);            }        },        onLeave: function(retval) {        }    });    Interceptor.attach(Module.findExportByName("libc.so", "fopen"), {        onEnter: function(args) {            var path1 = Memory.readCString(args[0]);            var path = path1.split("/");            var executable = path[path.length - 1];            var shouldFakeReturn = (RootBinaries.indexOf(executable) > -1)            if (shouldFakeReturn) {                Memory.writeUtf8String(args[0], "/ggezxxx");                send("Bypass native fopen >> "+path1);            }        },        onLeave: function(retval) {        }    });    Interceptor.attach(Module.findExportByName("libc.so", "system"), {        onEnter: function(args) {            var cmd = Memory.readCString(args[0]);            send("SYSTEM CMD: " + cmd);            if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id") {                send("Bypass native system: " + cmd);                Memory.writeUtf8String(args[0], "grep");            }            if (cmd == "su") {                send("Bypass native system: " + cmd);                Memory.writeUtf8String(args[0], "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled");            }        },        onLeave: function(retval) {        }    });    /*    TO IMPLEMENT:    Exec Family    int execl(const char *path, const char *arg0, ..., const char *argn, (char *)0);    int execle(const char *path, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);    int execlp(const char *file, const char *arg0, ..., const char *argn, (char *)0);    int execlpe(const char *file, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);    int execv(const char *path, char *const argv[]);    int execve(const char *path, char *const argv[], char *const envp[]);    int execvp(const char *file, char *const argv[]);    int execvpe(const char *file, char *const argv[], char *const envp[]);    */    BufferedReader.readLine.overload().implementation = function() {        var text = this.readLine.call(this);        if (text === null) {            // just pass , i know it's ugly as hell but test != null won't work :(        } else {            var shouldFakeRead = (text.indexOf("ro.build.tags=test-keys") > -1);            if (shouldFakeRead) {                send("Bypass build.prop file read");                text = text.replace("ro.build.tags=test-keys", "ro.build.tags=release-keys");            }        }        return text;    };    var executeCommand = ProcessBuilder.command.overload('java.util.List');    ProcessBuilder.start.implementation = function() {        var cmd = this.command.call(this);        var shouldModifyCommand = false;        for (var i = 0; i < cmd.size(); i = i + 1) {            var tmp_cmd = cmd.get(i).toString();            if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd.indexOf("mount") != -1 || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd.indexOf("id") != -1) {                shouldModifyCommand = true;            }        }        if (shouldModifyCommand) {            send("Bypass ProcessBuilder " + cmd);            this.command.call(this, ["grep"]);            return this.start.call(this);        }        if (cmd.indexOf("su") != -1) {            send("Bypass ProcessBuilder " + cmd);            this.command.call(this, ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"]);            return this.start.call(this);        }        return this.start.call(this);    };    if (useProcessManager) {        var ProcManExec = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File', 'boolean');        var ProcManExecVariant = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.lang.String', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'boolean');        ProcManExec.implementation = function(cmd, env, workdir, redirectstderr) {            var fake_cmd = cmd;            for (var i = 0; i < cmd.length; i = i + 1) {                var tmp_cmd = cmd[i];                if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") {                    var fake_cmd = ["grep"];                    send("Bypass " + cmdarr + " command");                }                if (tmp_cmd == "su") {                    var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"];                    send("Bypass " + cmdarr + " command");                }            }            return ProcManExec.call(this, fake_cmd, env, workdir, redirectstderr);        };        ProcManExecVariant.implementation = function(cmd, env, directory, stdin, stdout, stderr, redirect) {            var fake_cmd = cmd;            for (var i = 0; i < cmd.length; i = i + 1) {                var tmp_cmd = cmd[i];                if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") {                    var fake_cmd = ["grep"];                    send("Bypass " + cmdarr + " command");                }                if (tmp_cmd == "su") {                    var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"];                    send("Bypass " + cmdarr + " command");                }            }            return ProcManExecVariant.call(this, fake_cmd, env, directory, stdin, stdout, stderr, redirect);        };    }    if (useKeyInfo) {        KeyInfo.isInsideSecureHardware.implementation = function() {            send("Bypass isInsideSecureHardware");            return true;        }    }});

Hook frida 强制在主线程运行

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

强制让代码运行在主线程中

JSJava.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();  })})

Hook frida 指定方法中过滤打印

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

Hook 禁止 app 退出

JSfunction 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);

Hook 修改设备参数

JS// 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;    }	})

Hook 打印请求调用栈

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

Hook UI thread 注入

JSJava.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();  })})

常用打印转换

JS
//工具相关函数
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(/
|
/g, "").replace(/([da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ")));
}

function base64ToHex(str) {
    for (var i = 0, bin = base64Decode(str.replace(/[ 
]+$/, "")), 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
}

文章作者: Kevin
文章链接: http://example.com/fridahookjava/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 凡墙总是门!