Mac搭建Frida逆向开发环境

3,014 阅读1分钟

一、简介

Frida是一种基于Python+JavaScript的动态分析工具,可以用于逆向开发、应用程序的安全测试、反欺诈技术等领域,本质是一种动态插桩技术。Frida主要用于在已安装的应用程序上运行自己的JavaScript代码,从而进行动态分析、调试、修改等操作,能够绕过应用程序的安全措施实现应用程序进行逆向分析。

Frida可以适用于Android、Windows、iOS等各大操作系统,执行脚本基于Python或者Node.js写成,而注入代码用JavaScript写成,所以实现Frida逆向需要具备JavaScript、Python等语音基础。

二、环境搭建

安装Frida客户端

首先,我们需要下载Frida工具,Frida支持多个平台,包括Windows、Mac和Linux等。我们可以从Frida的官方下载也可以从官方Github地址下载。

image.png

除此之外,我们也可以使用pip命令进行安装,如下所示:

pip install frida

对于Android / iOS平台,则可以直接从Frida官方网站下载相应的安装包,下载链接:github.com/frida/frida…。其中,arm是真机调试用的,x86为模拟器调试用的。

image.png

启动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

链接成功会看到下面的输出:

image.png

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;
};