一、简介
Frida是一种基于Python+JavaScript的动态分析工具,可以用于逆向开发、应用程序的安全测试、反欺诈技术等领域,本质是一种动态插桩技术。Frida主要用于在已安装的应用程序上运行自己的JavaScript代码,从而进行动态分析、调试、修改等操作,能够绕过应用程序的安全措施实现应用程序进行逆向分析。
Frida可以适用于Android、Windows、iOS等各大操作系统,执行脚本基于Python或者Node.js写成,而注入代码用JavaScript写成,所以实现Frida逆向需要具备JavaScript、Python等语音基础。
二、环境搭建
安装Frida客户端
首先,我们需要下载Frida工具,Frida支持多个平台,包括Windows、Mac和Linux等。我们可以从Frida的官方下载也可以从官方Github地址下载。
- 官方地址:frida.re/
- 官方Github地址:github.com/frida/frida
除此之外,我们也可以使用pip命令进行安装,如下所示:
pip install frida
对于Android / iOS平台,则可以直接从Frida官方网站下载相应的安装包,下载链接:github.com/frida/frida…。其中,arm是真机调试用的,x86为模拟器调试用的。
启动Frida服务器
首先,使用adb命令测试手机是否连通,命令如下:
$ adb devices -l
接着,将下载的frida-server包push到手机中,最好是先执行root,运行如下命令:
$ adb root # might be required
$ adb push frida-server /data/local/tmp/
然后,执行adb shell命令进入设备的shell环境,cd到临时目录下,给frida-server设置可执行的权限,命令如下:
$ chmod 755 /data/local/tmp/frida-server
$ /data/local/tmp/frida-server &
我们可以使用下面的方式来验证是否安装成功,命令如下:
frida-ps -U
链接成功会看到下面的输出:
Frida的大致原理是手机端安装一个server程序,然后把手机端的端口转到PC端,PC端写python脚本进行通信,而python脚本中需要hook的代码采用javascript语言。
开发环境
接下来,我们运行如下的命令来搭建一个本地的开发环境:
$ git clone git://github.com/oleavr/frida-agent-example.git
$ cd frida-agent-example/
$ npm install
$ frida -U -f com.example.android --no-pause -l _agent.js
三、基本使用
连接Frida服务器
使用Python代码连接到Frida服务器。
import frida
device = frida.get_device_manager().enumerate_devices()[-1]
session = device.attach("com.example.app")
在设备列表中选择目标设备,使用attach()方法连接到指定的应用程序。
Hook某个函数
使用JavaScript代码Hook应用程序中的某个函数:
Interceptor.attach(Module.findExportByName("libexample.so", "example_func"), {
onEnter: function(args) {
console.log("example_func enter");
},
onLeave: function(retval) {
console.log("example_func leave");
}
});
该代码将Hook应用程序中名为example_func的函数,当进入函数时,会打印"example_func enter",当离开函数时,会打印"example_func leave"。
内存读取
使用JavaScript代码读取目标进程中的内存。
var addr = Module.findExportByName("libexample.so", "example_data");
var data = Memory.readByteArray(addr, 0x100);
console.log(hexdump(data));
该代码读取了名为example_data的变量,并将其打印到控制台上。
其他常见操作
劫持Java的函数调用:
Java.perform(function() {
var MainActivity = Java.use('com.example.MainActivity');
MainActivity.onCreate.implementation = function(savedInstanceState) {
console.log("[*] onCreate hooked");
this.onCreate(savedInstanceState);
};
var TextView = Java.use('android.widget.TextView');
TextView.setText.implementation = function(text) {
console.log("[*] setText hooked");
this.setText(text);
};
});
模拟按钮点击事件:
var button = Java.use('android.widget.Button');
var view = Java.cast(button.$new(), Java.use('android.view.View'));
Java.perform(function() {
view.performClick();
});
绕过SSL Pinning:
var SSLPinning = Java.use('com.example.SSLPinning');
SSLPinning.execute.overload('javax.net.ssl.SSLSocketFactory', 'java.lang.String', 'int').implementation = function(socketFactory, hostname, port) {
console.log("[*] SSLPinning.execute(" + socketFactory + ", " + hostname + ", " + port + ")");
var allowAllHostnameVerifier = Java.use('javax.net.ssl.HttpsURLConnection').getDefaultHostnameVerifier();
var nullarray = Java.array('java.lang.Object', [null]);
allowAllHostnameVerifier.verify(hostname, socketFactory.createSocket(hostname, port).getSession());
return true;
};