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
目录
- 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 注入
- 常用打印转换
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 进行内网穿透
-
nps server 启动
mac:
sudo nps start
-
新建客户端
安卓手机连接客户端
./npc -server=10.0.0.124:8024 -vkey=hm40rtjpf2j3c1up -type=tcp
-
给客户端添加和 frida server 的端口映射
安卓手机启动 frida-server:
./fs12800 -l 0.0.0.0:6666
将目标 frida-server 的端口映射到 56666 端口上
-
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 许可协议。转载请注明来自 凡墙总是门!