【Frida】【Android】08_爬虫之网络通信库okhttp3

🛫 系列文章导航

▒ 目录 ▒

🛫 导读

开发环境

版本号 描述
文章日期 2024-03-24
操作系统 Win11 - 22H2 22621.2715
node -v v20.10.0
npm -v 10.2.3
夜神模拟器 7.0.5.8
Android 9
python 3.9.9
frida 16.2.1
frida-tools 12.3.0
objection 1.11.0

1️⃣ 代码介绍

okhttp3主逻辑

implementation("com.squareup.okhttp3:okhttp:3.12.0")。

okhttp3的网络请求流程主要有以下几步:

  • 通过以下代码创建一个okhttpClient对象
  • 码创建一个Request请求对象
  • 端将Request请求封装成Call对象
  • 通过调用Call对象的enqueue()函数产生一次真实的网络请求,该参数接受一个Callback对象,用于处理响应结果。
java 复制代码
public class example {

    // TAG即为日志打印时的标签
    private static final String TAG = "r0ysue666";

    // 新建一个Okhttp客户端(不含拦截器等各种参数的OkHttpClient对象)
    // OkHttpClient client = new OkHttpClient();

    // 新建一个拦截器
    OkHttpClient client = new OkHttpClient.Builder()
            .addNetworkInterceptor(new LoggingInterceptor())
            .build();

    void run(String url) throws IOException {
        // 构造request
        Request request = new Request.Builder()
                .url(url)
                .header("token","r0ysue")
                .build();

        // 发起异步请求
        client.newCall(request).enqueue(
                new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        call.cancel();
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        //打印输出
                        Log.d(TAG, response.body().string());
                    }
                }
        );
    }
}

拦截器

拦截器是okhttp中的一个重要概念,okhttp通过Interceptor完成监控管理、重写和重试请求。每个网络请求和接收不管是GET还是PUT/POST等数据传输方式都必须经过okhttp3本身存在的五大拦截器,因此Interceptor是一个绝佳的Hook点,可以同时打印输出请求和响应。

下图就是okhttp3自带的五大拦截器:

拦截器链

下面的代码,是构造拦截器链的过程,可以看到:

  • 通过 addInterceptor() 方法添加的应用拦截器是放在最前面的。
  • 通过 addNetworkInterceptor() 方法添加的网络拦截器,则是在非 WebSocket 请求时,添加在 ConnectInterceptor 和 CallServerInterceptor 之间的。
java 复制代码
Response getResponseWithInterceptorChain() throws IOException {
  // Build a full stack of interceptors.
  // 收集拦截器的临时列表
  List<Interceptor> interceptors = new ArrayList<>();
  // 先添加通过 OkHttpClient.Builder # addInterceptor() 方法添加的拦截器
  interceptors.addAll(client.interceptors());
  interceptors.add(retryAndFollowUpInterceptor);
  interceptors.add(new BridgeInterceptor(client.cookieJar()));
  interceptors.add(new CacheInterceptor(client.internalCache()));
  interceptors.add(new ConnectInterceptor(client));
  if (!forWebSocket) {
    // 如果不是 WebSocket 请求,
    // 则添加通过 OkHttpClient.Builder # addNetworkInterceptor() 方法添加的拦截器
    interceptors.addAll(client.networkInterceptors());
  }
  interceptors.add(new CallServerInterceptor(forWebSocket));
  Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
      originalRequest, this, eventListener, client.connectTimeoutMillis(),
      client.readTimeoutMillis(), client.writeTimeoutMillis());
  return chain.proceed(originalRequest);
}

从上面我们可以看到.addNetworkInterceptor(new LoggingInterceptor())这样的代码,意思是给okhttp3增加网络拦截器。
LoggingInterceptor对象,将打印请求和响应相关的内容。

拦截器执行结果如下:

2️⃣ newCall自吐

本篇文章自带的资源是带拦截器的版本,可以查看拦截器运行的效果。

下面的内容,是通过不带拦截器的apk(下载地址:https://download.csdn.net/download/kinghzking/89067530)进行讲解,打印出我们想要的内容。

自吐frida脚本编写

从《源码介绍》中我们可以看出,OkHttpClient.newCall接受了一个request参数,该参数包含了我们关心的主要内容,所以我们直接拦截newCall即可打印出我们想要的结果,代码如下:

js 复制代码
    Java.perform(function() {
        var OkHttpClient = Java.use("okhttp3.OkHttpClient")
       
        OkHttpClient.newCall.implementation = function (request) {
            var result = this.newCall(request)
            console.log('[newCall] request = ', request.toString())
            return result
        };
    
    });

验证步骤

  • 通过frida -UF连接
  • 执行上面js语句
  • 点击apk中的发送请求按钮,显示拦截结果。
    效果如下图所示:

3️⃣ 拦截器自吐

前文已经说过,拦截器方式,可以更方便的实现请求内容的打印,我们如果将拦截器注入到目标APP中,将更通用而方便。

这种实现有两种方式:

  • LoggingInterceptor这部分代码翻译成JavaScript代码
  • 将编译好的dex通过Frida将注入其他应用中
    很明显,第二种更便于代码的编写和理解,我们也将以该方式进行演示。

获取dex文件

自吐frida脚本编写【通用高效】

  • 加载dex:Java.openClassFile
  • 获取LoggingInterceptor类:Java.use
  • 生成LoggingInterceptor对象:MyInterceptor.$new()
  • 获取OkHttpClient内部类Builder
  • 修改Builder.build实现
  • 在networkInterceptors()中增加拦截器LoggingInterceptor对象
js 复制代码
    Java.perform(function () {

        Java.openClassFile("/data/local/tmp/okhttp3logging.dex").load();

        var MyInterceptor = Java.use("com.r0ysue.okhttp3demo.LoggingInterceptor");

        var MyInterceptorObj = MyInterceptor.$new();
        var Builder = Java.use("okhttp3.OkHttpClient$Builder");
        console.log(Builder);
        Builder.build.implementation = function () {
            this.networkInterceptors().add(MyInterceptorObj);
            return this.build();
        };
        console.log("hook_okhttp3...");
    });

验证步骤

当我们通过frida交互模式,执行了上面代码的时候,发现并不会打印我们想要的结果:

这是因为,App只有一个全局对象client,一般在App启动的较早时机被创建,如果采用attach模式Hook okhttpClient,大概率会一无所获,因此只能用spawn模式来启动,对应的Frida命令必须使用-f参数。
执行命令:frida -U -f com.r0ysue.okhttp3demo -l hookInteceptor.js

再次点击发送请求按钮,熟悉的okhttpGET:日志又出现了:

📖 参考资料

相关推荐
兆。1 小时前
掌握 PyQt5:从零开始的桌面应用开发
开发语言·爬虫·python·qt
Winston Wood2 小时前
Android Parcelable和Serializable的区别与联系
android·序列化
清风徐来辽2 小时前
Android 项目模型配置管理
android
帅得不敢出门2 小时前
Gradle命令编译Android Studio工程项目并签名
android·ide·android studio·gradlew
problc3 小时前
Flutter中文字体设置指南:打造个性化的应用体验
android·javascript·flutter
API快乐传递者7 小时前
淘宝反爬虫机制的主要手段有哪些?
爬虫·python
帅得不敢出门13 小时前
安卓设备adb执行AT指令控制电话卡
android·adb·sim卡·at指令·电话卡
我又来搬代码了15 小时前
【Android】使用productFlavors构建多个变体
android
德育处主任17 小时前
Mac和安卓手机互传文件(ADB)
android·macos
芦半山17 小时前
Android“引用们”的底层原理
android·java