【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:日志又出现了:

📖 参考资料

相关推荐
阿巴斯甜2 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker3 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95274 小时前
Andorid Google 登录接入文档
android
黄林晴5 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab17 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿20 小时前
Android MediaPlayer 笔记
android
Jony_21 小时前
Android 启动优化方案
android
阿巴斯甜21 小时前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇21 小时前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android