frida-gum教程
frida-gum概述
frida-gum是基于inline-hook实现的
提供的功能:代码跟踪(Stalker)、内存访问监控(MemoryAccessMonitor)、符号查找、栈回溯实现、内存扫描、动态代码生成和重定位
inline Hook 原理
. 备份原指令,重写成为跳转指令
. 跳转到我们新的代码空间,把之前备份的指令执行一下。然后执行我们自己的逻辑(打印参数之类的)
. 跳回原程序空间,继续往下跑
例如,针对SVC系统调用指令:
参考:
https://bbs.kanxue.com/thread-268086.htm
Interceptor
Interceptor 是对 inline-hook 的封装,一般对native层的hook就直接使用Interceptor
例如
// 按地址读参数和返回值
Java.perform(function(){
var Offset=0xD543C4;
Interceptor.attach(Module.findBaseAddress(SoName).add(ptr(Offset)),{
onEnter: function(args) {
send("addr-" + Offset + " hooked ");
// 参数1
send("arg0 " + " - x0: " + this.context.x0);
var arg0_contnt = Memory.readU64(this.context.x0);
// send("arg0_contnt " + parseInt(arg0_contnt,16));
send(Memory.readByteArray(ptr(arg0_contnt),128));
// send(Memory.readByteArray(ptr(Memory.readU64(this.context.x0)),128));//ptr('0xEC644071'): 定义一个指针,指针地址为0xEC644071
send("arg1 " + " - x1: " + this.context.x1);
var arg1_contnt = Memory.readU64(this.context.x1);
send(Memory.readByteArray(ptr(arg1_contnt),128));
send("arg2 " + " - x2: " + this.context.x2);
var arg2_contnt = Memory.readU64(this.context.x2);
send(Memory.readByteArray(ptr(arg2_contnt),128));
},
onLeave: function(retval){
console.log(Offset +" finished \\n");
send("arg2 " + " - x2: " + this.context.x2);
}
});
});
Stalker 潜行者
可以跟踪指定线程,规定特定event发生时的行为
基本使用:
Interceptor.attach(addr, {
onEnter: function (args) {
this.args0 = args[0];
this.tid = Process.getCurrentThreadId();//获取线程ID
//跟随
Stalker.follow(this.tid, {
events: {//事件
call: true,//调用
ret: false,//返回
exec: true,//执行
block: false,//块
compile: false//编译
},
//接收时间
onReceive(events){
for (const [index,value] of Stalker.parse(events)) {
console.log(index,value);
}
}
});
}, onLeave: function (retval) {
Stalker.unfollow(this.tid);
}
});
MemoryAccessMonitor 内存读写监视器
MemoryAccessMonitor可以监控 对目标内存区间的访问,在目标内存区间有读写行为时,用户指定的回调函数会被触发
本质上是将目标内存页设置为不可读写,这样在发生读写行为时会触发事先注册好的中断处理函数,其中会调用到用户使用 gum_memory_access_monitor_new 注册的回调方法中。
比如,找到了一个字符串,但是找不到该字符串的Xref(也就是读写该字符串的地方)
这个时候可以用frida监听该内存区域(0x581799)上的读写,来判断哪些函数使用了该字符串:
MemoryAccessMonitor.enable({
base:libjni.base.add(0x581799),
size:12
},{
onAccess: function(details) {
console.log("0x" + (details.from - libjni.base).toString(16))
}
})
这种方法会一次修改一个内存页,并且触发一次就失效了
参考:
https://bbs.kanxue.com/thread-273450.htm
https://blog.csdn.net/weixin_56039202/article/details/127041865