第一次尝试frida

前言

大概半个月前,群里的一个小伙伴问,谁能把某电商APP的订单列表导出到电脑,有个私活,报个价。其实我对这种稍微有点了解,无非是抓包,破解。但通常App的网络请求会有一套签名验证机制,所以要想模拟出整套请求流程,也算比较复杂。和群里的讨论后,觉得用hook做合适,但群里和我一样,都是安卓开发,没有逆向工程师,首先想到的是xposed。

xposed太重

我之前倒是写过xposed,xposed缺点有两个,第一就是环境复杂,你得安装xposed环境才可以,目前都是通过virtual xposed来使用。再就是插件一但有修改,就得重启手机。不过这也带来了一个有点就是持久化,只要装进去,就一直存在。那有没有更轻量级的工具可以达到这种效果,后来在网上找到了frida。(这也好几年了,我居然不知道)

Frida

官网
https://github.com/frida/frida/releases
https://frida.re

环境搭建

Frida分为客户端(电脑) + 服务端(手机端)。

1
2
3
4
pip3 install frida
pip3 install frida-tools
# 安装完成后运行,查看是否安装成功,有进程输出说明成功
frida-ps -U

下载服务端程序到手机(模拟器),必须有root权限。下载时注意选择你对应平台的frida-server

1
2
3
4
5
adb push frida-server /data/local/tmp/
adb shell
su
chmod 777 /data/local/tmp/frida-server
/data/local/tmp/frida-server

注入js,hook

举一个hook okhttp的例子,okhttp的响应信息都打印出来。在电脑上新建一个test.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// test.js  hook okhttp 因为okhttp的response只能消费一次,为了不影响默认的程序,将buffer复制一份
function get_http(){
Java.perform(function (){
var RealCall = Java.use("okhttp3.RealCall");
var Buffer = Java.use("okio.Buffer");
var ResponseBody = Java.use("okhttp3.ResponseBody");

RealCall.getResponseWithInterceptorChain.overload().implementation = function () {
var response = this.getResponseWithInterceptorChain();
var responseBody = response.body();

var buffer = Buffer.$new();
responseBody.source().readAll(buffer);
var responseBodyString = buffer.readUtf8();
console.log("HTTP Request -> " + this.request().url().toString());
console.log("HTTP Response -> " + responseBodyString);

var builder = response.newBuilder();

var newResponse = builder.body(ResponseBody.create(responseBody.contentType(), responseBodyString)).build();
return newResponse;
}
});

}

启动服务端后,在客户端(电脑)上运行

1
2
3
4
# U是USB F是当前app,这里用-n也不会重启(frida-ps查到的名字),用-f 包名 会重启app
frida -UF test.js
# 运行后,会进入frida,我们还需要输入具体js函数,比如get_http()
get_http()

关于frida的语法,简单介绍一个常用的,剩下的上官网查。

1
2
3
4
5
var Class = Java.use("class name");
Class.method.overload("param class name").implementation = function( param) {
# param.xxxx
# console.log("");
}