本篇用于记录我在使用frida时的一些脚本,以便后续查阅。
目录
一、代码结构
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
src = """
Java.perform(
function test(){
var v = Java.androidVersion;
send('Version:' + v)
console.log("process pid = " + Process.id);
}
);
"""
dev = frida.get_usb_device()
pid = dev.spawn("com.example")
process = frida.get_usb_device().attach(pid)
script = process.create_script(src)
script.on('message', on_message)
print('[*] HooK Start running')
script.load()
dev.resume(pid)
sys.stdin.read()
src 中即为js脚本内容,在启动frida时使用了resume是因为需要hook一些启动时只执行一次的函数,正常情况下不需要这一步。
二、脚本
(1)常用函数Hook
HashMap
var HashMap = Java.use('java.util.HashMap');
HashMap.get.implementation = function(key) {
if(key !== null){
let keyStr = (key.toString())
if (keyStr.includes("xxx") || keyStr.includes("xxx")){
console.log("HashMap get() called with key: " + keyStr);
var result = this.get(key);
console.log("HashMap get() returned: " + result);
return result;
}else{
var result = this.get(key);
return result;
}
}
var result = this.get(key);
return result;
};
HashMap.put.implementation = function(key, value) {
if(key !== null){
let keyStr = (key.toString())
if (keyStr.includes("xxx")){
console.log('put function called with key: ' + key + ' and value: ' + value);
return this.put(key, value);
}else{
return this.put(key, value);
}
}
return this.put(key, value);
};
此处加入了一些判断,懒得删了
ConcurrentHashMap
var ConcurrentHashMap = Java.use('java.util.concurrent.ConcurrentHashMap');
ConcurrentHashMap.get.implementation = function(key) {
let keyStr = (key.toString())
if(keyStr.includes("xxx")){
console.log('ConcurrentHashMap.get 方法被调用,key: ' + key);
var result = this.get(key);
console.log('ConcurrentHashMap.get result ' + result);
var resultClass = result.getClass();
var fields = resultClass.getDeclaredFields();
for (var i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
var fieldName = fields[i].getName();
var fieldValue = fields[i].get(result);
console.log(fieldValue.getClass().getName());
console.log(fieldName + ': ' + fieldValue);
}
return result;
}else{
var result = this.get(key);
return result;
}
};
也加入了一些筛选,并能通过反射获取obj的字段及字段值
(2)可能用到的脚本
打印Map的值
var HashMap = Java.use('java.util.HashMap');
let A= Java.use("com.example.A");
A["a"].overload('int', '[B', 'java.util.Map').implementation = function (i2, bArr, map) {
console.log(`A.a is called: i2=${i2}, bArr=${bArr}, map=${map}`);
let result = this["a"](i2, bArr, map);
console.log("A.a.map:" + Java.cast(map, HashMap).toString());
console.log(`a.a result=${result}`);
return result;
};
打印调用堆栈
function printstack() {
send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()))
}
let B = Java.use("com.example.B");
B["a"].overload('java.lang.String', 'java.lang.String').implementation = function (str, str2) {
console.log(`B.a is called: str=${str}, str2=${str2}`);
let result = this["a"](str, str2);
console.log(`B.a result=${result}`);
/*printstack();*/
return result;
};
想要打印堆栈把注释去了即可。
(3)hook初始化函数
var HashMap = Java.use('java.util.HashMap');
let C = Java.use("com.example.C");
C["$init"].implementation = function (map) {
console.log(`C.$init is called: map=${map}`);
console.log("C.map:" + Java.cast(map, HashMap).toString());
this["$init"](map);
};
(3)需要注意的地方
目前我想到的需要注意的地方,首先注意有没有多个实现,有的话加上overload,然后有些native函数的hook也是可以hook到的,再就是注意frida版本,版本低了可能有些东西hook不到,也不一定吧,只是可能。
三、总结
只是自己用的脚本的一些总结,也许还会往里面加点儿以后?最后感谢jadx,能直接给我frida代码(不会还有人不知道jadx右键能自己生成firda代码吧)
2024.6.14