By ruanruan,2022.04.19
0x00 前言
下面是学习用Frida hook Native层的导出函数和未导出函数的记录。
demo下载链接:https://pan.baidu.com/s/1ZCIeJXzeTpQ8uJ9Ew5nnGQ
提取码:z94i
0x01 Hook导出函数
1、apk相关信息
关键代码:
用IDA分析,查找函数
点击按钮,实现1+2=3的功能
2、js代码
修改输出值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);//将输出值替换为10000send(retval.toInt32());} });
});
retval对象只在 onLeave函数作用域范围内有效。
3、frida hook
一般顺序为:
手机运行frida
转发端口
adb forward tcp:27043 tcp:2703
手机运行app
查看pid,执行hook脚本
frida-ps -U
frida -U -l fridaso.js 22467
点击按钮。
命令行和app都能看到被篡改的结果为10000,而不是3。
也可以先点击按钮,再执行hook脚本。
4、踩坑
遇到的问题:
(1)python代码不能根据包名指定进程
(2)不能通过pid查找进程
(3)找不到基地址
解决:
后两个问题在确定js脚本没有问题,更换模拟器为测试机后,可以成功hook
第一个问题在之后需注意,使用python脚本进行hook时不能指定pid,在调用进程时按照包名查找不一定成功,最好还是用js脚本指定相应pid进行hook。
0x02 Hook未导出函数
1、apk相关信息
页面功能:
点击按钮显示3
MainActivity:
进一步查看
在Ghidra查看该函数
2、查看函数地址
(1)通过IDA查看地址
脚本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); } });
});
(2)通过Ghidra查看地址(X86_64)
脚本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()); } });
});
(3)最终版
-
通过已导出的hook方法获得地址值
得到偏移地址为
0x7966b8d5dc
-
通过Ghidra查看地址(arm64)
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结果:
3、修改返回值
找到正确的偏移地址,再修改返回值就很简单了
(1)hook.js
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());} });
});
(2)运行结果
(3)APP显示
4、踩坑记录
(1)环境相关
A、测试机安装同电脑版本的magiskfrida报错
解决:搜索引擎搜不到相关报错,但从错误来看 会比较底层。最终通过安装高版本的magiskfrida解决
B、很多报错能通过修改时间解决,但是在使用NTP时间服务器来修改时间但不准确
原因是刷机时的时区设置问题,修改时区即可解决
(2)脚本相关
A、如何正确查看偏移地址问题
要根据所用测试机、模拟器的系统架构(arm64、X86…),来选择对应的so文件,再用Ghidra分析查看函数地址。
直接运行frida命令查看只会返回基地址和偏移量地址,进不了Interceptor接口
如果地址错误就会一直报错:拦截器找不到该地址的函数,说明是找的偏移地址错了。
B、frida命令参数–no-pause
进程直接执行
对比是否使用–no-pause参数,在这个场景对参数地址的运行结果影响不大
使用参数运行:
不用参数运行:
(3)小技巧
- 遇到问题看官方文档:https://frida.re/docs/gadget/
- 在cmd调试hook脚本时会更快发现问题
- frida-ps -U查看app进程时可以加个a来查看当前正在运行的进程软件:frida-ps -Ua
0x03 总结
Hook导出函数主要是根据so文件中函数名来确定被Hook的函数,较为简单。而Hook 未导出函数是根据函数偏移量来确定被Hook的函数,但是一定要注意在使用工具反编译时要选对架构。也可以用Hook 未导出函数的方法来Hook导出函数。