frida hook笔记¶
中途启动hook¶
import sys
import frida
with open('hook_newSign_v1.js', 'r',encoding='utf-8') as f:
jsHookCode = f.read()
# 中途启动
redv = frida.get_remote_device()
s = redv.attach('酷安')
script = s.create_script(jsHookCode)
script.load()
sys.stdin.read()
# 或
# device = frida.get_usb_device(-1)
# process = device.attach('酷安')
# script = process.create_script(jsHookCode)
# # script.on('message', )
# print(f'[*] running')
# script.load()
# device.resume(pid)
# sys.stdin.read()
hook APP重启阶段¶
spawn方式重启APP, hook APP的启动阶段
import sys
import frida
with open('hook_newSign_v1.js', 'r',encoding='utf-8') as f:
jsHookCode = f.read()
device = frida.get_usb_device(-1)
pid = device.spawn(['com.coolapk.market'])
process = device.attach(pid)
script = process.create_script(jsHookCode)
# script.on('message', )
print(f'[*] running')
script.load()
device.resume(pid)
sys.stdin.read()
访问外部类的成员变量¶
使用js脚本调用方法¶
apktool¶
androidkiller¶
打印调用堆栈¶
function print_stack() {
// java打印堆栈
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
// SO打印堆栈
console.log('called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');
}
调用方式
Java.perform(function () {
var num = 1
let AuthUtils = Java.use("com.coolapk.market.util.AuthUtils");
AuthUtils["getAS"].implementation = function (context, str) {
console.log(num, 'getAS is called' + ', ' + 'context: ' + context + ', ' + 'str: ' + str);
let ret = this.getAS(context, str);
console.log(num, 'getAS ret value is ' + ret);
print_stack();
num += 1;
return ret;
};
function print_stack() {
// java打印堆栈
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
// SO打印堆栈
console.log('called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');
}
})
反射调用¶
obj.getClass().getMethod("方法名字符串",new Class[0]).invoke(obj, new Object[0]);
context.getClass().getMethod("getPackageManager", new Class[0]).invoke(context, new Context[0]);
参考文档¶
java.lang.Class class类
安卓开发API官网
安卓开发API手册(中文) matools.com/api/android
java API
新建实例化对象¶
打印object¶
一¶
1 确定object类型, console.log(p.$className) 查看p的数据类型
2 Java.cast() 强制转换p的对应类型
3 调用该类的输出方法, 通常都有一个toString()方法
二¶
使用js的json类
尝试console.log(JSON.stringify(p))
可能打印不出来字符串, 一般能打印p的字节数组(可以用数据和真实数据进行对比)
三¶
bytes array是object
String 和 bytes array可以相互转化
new String(bytes) bytes转换为字符串. 本身如果是不可打印的字符串, 打印是乱码
hook so¶
Java.perform(function () {
var so = Module.getExportByName('liba.so', 'Java_com_coolapk_market_util_AuthUtils_getAS');
Interceptor.attach(so, {
onEnter: function (args) {
console.log(`3: ${args[3]}`)
},
onLeave: function (retval) {
}
})
})
hook jni¶
hook类的所有方法¶
Java.perform(function () {
hook_class('com.coolapk.market.AppConfig');
});
function hook_class(className) {
var myClass = Java.use(className);
var methods = myClass.class.getDeclaredMethods();
methods.forEach(function (method) {
var methodName = method.getName();
// 获取所有重载
var overloads = myClass[methodName].overloads;
overloads.forEach(function (overload) {
overload.implementation = function () {
// arguments js自带的形参的集合
// argumentsType 自带的形参类型的集合
for (let i = 0; i < arguments.length; i++) {
console.log(`[${methodName}] > ${i} > [${overload.argumentTypes[i].className}] : > ${arguments[i]}`);
}
var ret = this[methodName].apply(this, arguments);
console.log(`[${methodName}] return: ${ret}`);
return ret;
}
});
// console.log(methodName);
})
}
打印调用堆栈这些
Java.perform(function () {
hook_class('com.coolapk.market.AppConfig');
});
function hook_class(className) {
var myClass = Java.use(className);
var methods = myClass.class.getDeclaredMethods();
methods.forEach(function (method) {
var methodName = method.getName();
// 获取所有重载
var overloads = myClass[methodName].overloads;
overloads.forEach(function (overload) {
overload.implementation = function () {
console.log(`[${methodName}] 调用堆栈: `)
print_stack()
// arguments js自带的形参的集合
// argumentsType 自带的形参类型的集合
for (let i = 0; i < arguments.length; i++) {
// 打印堆栈
console.log(`[${methodName}] > ${i} > [${overload.argumentTypes[i].className}] : > ${arguments[i]}`);
// JSON.stringify()打印一次
console.log(`[${methodName}] > ${i} > [${overload.argumentTypes[i].className}] : > ${JSON.stringify(arguments[i])}`);
}
var ret = this[methodName].apply(this, arguments);
console.log(`[${methodName}] return: ${ret}`);
return ret;
}
});
// console.log(methodName);
})
function print_stack() {
// java打印堆栈
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
// SO打印堆栈
// console.log('called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');
}
}
jadx有代码, 但hook不到类¶
可能动态加载dex, 类可能在另外的classloader中, 需切换到classloader再hook
classloader
Java.enmerateClassLoaders()
通用加解密hook¶
搜: frida hook所有加密类