被hook的内容,需要放在Java.perform中
function hook_java() {
Java.perform(function () {
});
}
一般被hook的内容
var LoginActivity = Java.use("类名");
// hook指定的重载方法
LoginActivity.a.overload('java.lang.String', 'java.lang.String').implementation = function (str, str2) {
//调用原来的函数
var result = this.a(str, str2);
return result; // 返回结果
};
主动调用
//主动调用静态方法
var clazz = Java.use("类名");
//设置静态成员变量
clazz.static_var.value = something;
// 调用静态方法
clazz.static_func();
// 主动调用非静态方法
Java.choose("类名", {
onMatch: function (instance) {
instance.nonStaticFunc(arg);
},
onComplete: function () {
}
});
hook内部类
var InnerClasses = Java.use("com.abc.abc$InnerClasses");
hook 类的多个函数
var clazz = Java.use(class_name);
var all_methods = clazz.class.getDeclaredMethods();
for (var i = 0; i < all_methods.length; i++) {
var method = (all_methods[i]);
var methodStr = method.toString();
var substring = methodStr.substr(methodStr.indexOf(class_name) + class_name.length + 1);
var methodname = substring.substr(0, substring.indexOf("("));
InnerClasses[methodname].implementation = function () {
}
}
设置有相同函数名的成员变量的值
// 需要在变量名前加下划线
instance._same_name_bool_var.value = true;
hook 动态加载的dex
Java.enumerateClassLoaders({
onMatch: function (loader) {
try {
if (loader.findClass("类名")) {
console.log(loader);
Java.classFactory.loader = loader; //切换classloader
}
} catch (error) {
}
}, onComplete: function () {
}
});
枚举Class
Java.enumerateLoadedClasses({
onMatch: function (name) {
if (name.indexOf("类名") >= 0) {
console.log(name);
}
}, onComplete: function () {
}
})
frida启动
// spawn 启动app
frida -U --no-pause -f com.package.abc --l hook.js
hook构造方法
var a = Java.use("类名");
//hook 构造函数
a.$init.implementation = function (a,b,c) {
this.$init(a,b,c);
};
打印堆栈
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
动态加载dex
Java.openClassFile("/data/local/tmp/dex.dex").load();
class转jar,转dex
jar -cvf something.jar something.class
dx --dex --output=something.dex something.jar
android_ndk 下的 d8 命令,直接class ——> dex
hook native func
// 知道函数名,函数符号导出
var v_funcName = Module.findExportByName("libnative.so", "funcName");
//hook模块的导出函数
Interceptor.attach(v_funcName, {
onEnter: function (args) {
// TODO
}, onLeave: function (retval) {
}
});
// 函数未导出
var base_libnative = Module.findBaseAddress("libnative.so.so");
var sub_func = base_libnative.add(funcAddr_In_so); // 加函数的偏移地址 thumb需要实际地址加1
Interceptor.attach(sub_func, {
onEnter: function (args) {
// TODO
}, onLeave: function (retval) {
}
});
// 批量hook
var module_libart = Process.findModuleByName("libart.so");
var symbols = module_libart.enumerateSymbols(); //枚举模块的符号
var addr_GetStringUTFChars = null;
var addr_FindClass = null;
var addr_GetStaticFieldID = null;
var addr_SetStaticIntField = null;
for (var i = 0; i < symbols.length; i++) {
var name = symbols[i].name;
if (name.indexOf("art") >= 0) {
if ((name.indexOf("CheckJNI") == -1) && (name.indexOf("JNI") >= 0)) {
if (name.indexOf("GetStringUTFChars") >= 0) {
console.log(name);
addr_GetStringUTFChars = symbols[i].address;
} else if (name.indexOf("FindClass") >= 0) {
console.log(name);
addr_FindClass = symbols[i].address;
} else if (name.indexOf("GetStaticFieldID") >= 0) {
console.log(name);
addr_GetStaticFieldID = symbols[i].address;
} else if (name.indexOf("SetStaticIntField") >= 0) {
console.log(name);
addr_SetStaticIntField = symbols[i].address;
}
}
}
}
// 将c函数转成js可以调用的样子
var addr_fopen = Module.findExportByName("libc.so", "fopen");
var addr_fputs = Module.findExportByName("libc.so", "fputs");
var addr_fclose = Module.findExportByName("libc.so", "fclose");
var fopen = new NativeFunction(addr_fopen, "pointer", ["pointer", "pointer"]);
var fputs = new NativeFunction(addr_fputs, "int", ["pointer", "pointer"]);
var fclose = new NativeFunction(addr_fclose, "int", ["pointer"]);
var filename = Memory.allocUtf8String("/sdcard/reg.dat");
var open_mode = Memory.allocUtf8String("w+");
var file = fopen(filename, open_mode); // 这个
从地址获取字符串
var c_String = ptr(0x1234).readCString()
一些字符串处理
TODO
frida 的api来写文件
var file = new File("/sdcard/txt.txt", "w");
file.write("12345abcd");
file.flush();
file.close();
打印Java对象的内容
/*
打印Java对象的内容,使用gson包,使用方法如下
参考 https://github.com/qiang/AndroidSecurityStudy
https://bbs.pediy.com/thread-259186.htm
*/
Java.openClassFile("/data/local/tmp/r0gson.dex").load();
const gson = Java.use("com.r0ysue.gson.Gson");
console.log(gson.$new().toJson(XXX));
// 或者
JSON.stringify()
frida中构造Java数组
var values = Java.array('int', [100, 101, 102]);
接口interface、Java.register
// 被hook的apk中存在一个接口,frida可以使用这个接口动态的创建一个类
var beer = Java.registerClass({
name : 'com.android.beer', // 动态创建的类的类名
implements : [Java.use('com.android.water')], // apk中接口类的类名
methods : {
funcA : function(arg1,arg2){
},
funcB : function(arg1,arg2){
return arg1 + arg2;
},
}
});
// 如何使用
console.log("beer.funcA :" , beer.$new().funcA());
Remote Procedure Call 远程调用
function invoke(){
Java.perform(function(){
Java.choose("",{
onMatch:function(instance){
instance.secret();
},onComplete:function(){}
})
})
}
source = """
rpc.exports = {
add: function (a, b) {
return a + b;
},
sub: function (a, b) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(a - b);
}, 100);
});
}
invokeFunc:invoke
};
"""
script = session.create_script(source) # 加载脚本
script.on('message', on_message)
script.load()
print(script.exports.add(2, 3)) # 远程调用
print(script.exports.sub(5, 3))
session.detach()
动态修改
Java.perform(function () {
var tv_class = Java.use("android.widget.TextView");
tv_class.setText.overload("java.lang.CharSequence").implementation = function (x) {
var string_to_send = x.toString();
var string_to_recv;
send(string_to_send); // 将数据发送给kali主机的python代码
recv(function (received_json_object) {
string_to_recv = received_json_object.my_data
console.log("string_to_recv: " + string_to_recv);
}).wait(); //收到数据之后,再执行下去
return this.setText(string_to_recv);
}
});
import time
import frida
def my_message_handler(message, payload):
print message
print payload
if message["type"] == "send":
print message["payload"]
data = message["payload"].split(":")[1].strip()
print 'message:', message
data = data.decode("base64")
user, pw = data.split(":")
data = ("admin" + ":" + pw).encode("base64")
print "encoded data:", data
script.post({"my_data": data}) # 将JSON对象发送回去
print "Modified data sent"
device = frida.get_usb_device()
pid = device.spawn(["com.roysue.demo04"])
device.resume(pid)
time.sleep(1)
session = device.attach(pid)
with open("s4.js") as f:
script = session.create_script(f.read())
script.on("message", my_message_handler) # 注册消息处理函数
script.load()
raw_input()
TODO