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 启动
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 普通方法
function 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 重载方法
function 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 构造方法
function 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 对象
function 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 动静态成员属性
function 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 内部类
function 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 匿名类
// 接口, 抽象类, 不可以被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()
function 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()
function 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 类的所有方法及重载
function 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
function 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, 可以使用以下代码:
function 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 主动构造数组
function 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 强制类型转换
// 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 打印类实现的接口
function 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("\t", interfaceList[i].toString());
// 直接打印接口名称
}
}
}
}
})
})
}
Hook enum 枚举
function 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
function 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 主动调用构造方法
function 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 主动调用静态方法
function 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 主动调用动态方法
// 非静态方法的主动调用 自定义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 交互
frida 传递参数
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代码
python 处理收到的参数
# -*- coding: utf-8 -*-
import sysimport time
import base64
import frida
from loguru import logger
def 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
// 打印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 数组
// 1. 使用 java.util.Arrays 的 toString 方法 打印 [C
// 2. 使用 js 的 JSON.stringify 打印 [C
function 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
//遍历打印
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打印 HashMap
function 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()
打印
function 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 数组
//方法 1
function 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() 打印 [B
function 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
}
})
}
//方法 3
function printByteArray(byteArray){
Java.perform(function(){
var ByteString = Java.use("com.android.okhttp.okio.ByteString");
console.log(ByteString.of(byteArray).hex())
})
}
Hook 打印调用栈
function 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 打印
function 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
int ֏(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 内存打印
内存漫游, 打印实例的字段和方法
function 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("\t Fields:")
for (var i in fields){
console.log("\t\t" + fields[i].toString());
}
console.log("\t Methods:")
for (var i in methods){
console.log("\t\t" + 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
Java.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
var 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
Java.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 检测
// $ 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.so
Java.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 退出
function 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 修改设备参数
// 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 打印请求调用栈
var 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 注入
Java.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(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ")));
}
function base64ToHex(str) {
for (var i = 0, bin = base64Decode(str.replace(/[ \r\n]+$/, "")), 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 许可协议。转载请注明来自 凡墙总是门!