By ruanruan,2022.04.19
so文件当中的函数,分为导出函数和未导出函数两种,导出函数打开IDA后能够在导出表中找到的函数就是导出函数,未导出函数则在导出表中寻找不到,一般来说静态编写的native函数都能在导出表中寻找到,而动态加载的则无法在导出表中发现
下面是学习用Frida hook Native层的导出函数和未导出函数的记录。
demo下载链接:https://pan.baidu.com/s/1ZCIeJXzeTpQ8uJ9Ew5nnGQ
提取码:z94i
关键代码:
用IDA分析,查找函数
点击按钮,实现1+2=3的功能
修改输出值3为指定值。
Java.perform(function(){
//下面这一句代码是指定要Hook的so文件名和要Hook的函数名,函数名即IDA导出表中显示的函数名
var nativePointer = Module.findExportByName("libfridaso.so", "Java_com_example_fridaso_FridaSoDefine_FridaSo");
send("native: " + nativePointer);
Interceptor.attach(nativePointer, {
onEnter: function(args){
//进入该函数前要执行的代码,第三个参数才是传入的参数
send(args[0]);
send(args[1]);
send(args[2].toInt32());
send(args[3].toInt32());
//send(args[4].toInt32());
},
onLeave: function(retval){
send(retval.toInt32());
retval.replace(10000);//将输出值替换为10000
send(retval.toInt32());
}
});
});
retval对象只在 onLeave函数作用域范围内有效。
一般顺序为:
手机运行frida
转发端口
adb forward tcp:27043 tcp:2703
手机运行app
查看pid,执行hook脚本
frida-ps -U
frida -U -l fridaso.js 22467
点击按钮。
命令行和app都能看到被篡改的结果为10000,而不是3。
也可以先点击按钮,再执行hook脚本。
遇到的问题:
(1)python代码不能根据包名指定进程
(2)不能通过pid查找进程
(3)找不到基地址
解决:
后两个问题在确定js脚本没有问题,更换模拟器为测试机后,可以成功hook
第一个问题在之后需注意,使用python脚本进行hook时不能指定pid,在调用进程时按照包名查找不一定成功,最好还是用js脚本指定相应pid进行hook。
页面功能:
点击按钮显示3
MainActivity:
进一步查看
在Ghidra查看该函数
脚本1.1:
Java.perform(function(){
var soAddr = Module.findBaseAddress("libfridaso.so");
send('soAddr: ' + soAddr);
var MD5FinalAddr = soAddr.add(0x0770+1);
//1768为函数偏移量
send('MD5FinalAddr: ' + MD5FinalAddr);
Interceptor.attach(MD5FinalAddr, {
onEnter: function(args){
send(args[0]);
send(args[1]);
},
onLeave: function(retval){
send(retval);
}
});
});
脚本1.2:
Java.perform(function(){
var soAddr = Module.findBaseAddress("libfridaso.so");
send('soAddr: ' + soAddr);
var MD5FinalAddr = soAddr.add(0x05cf+1);
//1768为函数偏移量
send('MD5FinalAddr: ' + MD5FinalAddr);
Interceptor.attach(MD5FinalAddr, {
onEnter: function(args){
send(args[0]);
send(args[1]);
send(args[2].toInt32());
send(args[3].toInt32());
},
onLeave: function(retval){
send("result: "+retval.toInt32());
}
});
});
Java.perform(function(){
var soAddr = Module.findBaseAddress("libfridaso.so");
send('soAddr: ' + soAddr);
var MD5FinalAddr = soAddr.add(0x05db+1);
//1768为函数偏移量
send('MD5FinalAddr: ' + MD5FinalAddr);
Interceptor.attach(MD5FinalAddr, {
onEnter: function(args){
send("111");
send(args[0]);
send(args[1]);
send(args[2].toInt32());
send(args[3].toInt32());
},
onLeave: function(retval){
send("result: "+retval.toInt32());
}
});
});
hook结果:
找到正确的偏移地址,再修改返回值就很简单了
Java.perform(function(){
var soAddr = Module.findBaseAddress("libfridaso.so");
send('soAddr: ' + soAddr);
var MD5FinalAddr = soAddr.add(0x05db+1);
//1768为函数偏移量
send('MD5FinalAddr: ' + MD5FinalAddr);
Interceptor.attach(MD5FinalAddr, {
onEnter: function(args){
send(args[0]);
send(args[1]);
send(args[2].toInt32());
send(args[3].toInt32());
},
onLeave: function(retval){
send("result1: "+retval.toInt32());
retval.replace(2022);
send("result2: "+retval.toInt32());
}
});
});
解决:搜索引擎搜不到相关报错,但从错误来看 会比较底层。最终通过安装高版本的magiskfrida解决
原因是刷机时的时区设置问题,修改时区即可解决
要根据所用测试机、模拟器的系统架构(arm64、X86…),来选择对应的so文件,再用Ghidra分析查看函数地址。
直接运行frida命令查看只会返回基地址和偏移量地址,进不了Interceptor接口
如果地址错误就会一直报错:拦截器找不到该地址的函数,说明是找的偏移地址错了。
进程直接执行
对比是否使用–no-pause参数,在这个场景对参数地址的运行结果影响不大
使用参数运行:
不用参数运行:
Hook导出函数主要是根据so文件中函数名来确定被Hook的函数,较为简单。而Hook 未导出函数是根据函数偏移量来确定被Hook的函数,但是一定要注意在使用工具反编译时要选对架构。也可以用Hook 未导出函数的方法来Hook导出函数。