环境搭建

build 中引入即可

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

主要用到的类是这几个

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

使用流程

  • OkHttpClient 对象
OkHttpClient client = new OkHttpClient();
用于配置 OKhttp 框架的各种配置。 当然你可以如上使用默认配置,只初始化就行了。 (也可以配置超时,重连等配置如下)
OkHttpClient client = new OkHttpClient.Builder()
        .addNetworkInterceptor(new LoggingInterceptor()) // 配置日志拦截器
        .readTimeout(5. TimeUnit.SECONDS) // 设置读超时
        .writeTimeout(5. TimeUnit.SECONDS) // 设置写超时
        .connectTimeout(5. TimeUnit.SECONDS) // 设置连接超时
        .retryOnConnectionFailure(true) // 自动重连
        .build();
// 还有其他配置,这里不详细写了
// 设置代理,SSL验证,协议版本验证等,也能自定义配置。

  • Request 对象
Request request = new Request.Builder()
        .url(url)
        .build();
配置
Request request = new Request.Builder()
        .url(url)
        .header(key, value)
        .header(key, value) // 同理可以配置各种请求头
        .build();
  • 发送异步请求
将 Request 封装成 Call 对象后,每次 enqueue 队列中都会产生一次真实的网络请求。(这里主要用的是异步)
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());
        }
    }
);


通过调试app可以成功访问百度了

Hook

  • 时机1: request 构建过程
  • 时机2: newCall

    Java.perform(function () {
          var OkHttpClient = Java.use('okhttp3.OkHttpClient');
          OkHttpClient.newCall.implementation = function(request){
              var result = this.newCall(request);
              console.log(request.toString());  // 大部分 object 都支持 toString()
              return result;
          }
    });

  • 时机3: 自带的拦截器, okhttp 自带5大拦截器类似中间件,可以通过 hook 拦截器来拿到想要的数据

    Java.perform(function () {
          var ByteString = Java.use("com.android.okhttp.okio.ByteString");
          var Buffer = Java.use("com.android.okhttp.okio.Buffer");
          var Interceptor = Java.use("okhttp3.Interceptor");
          var MyInterceptor = Java.registerClass({
              name: "okhttp3.MyInterceptor",
              implements: [Interceptor],
              methods: {
                  intercept: function (chain) {
                      var request = chain.request();
                      try {
                          console.log("MyInterceptor.intercept onEnter:", request, "\nrequest headers:\n", request.headers());
                          var requestBody = request.body();
                          var contentLength = requestBody ? requestBody.contentLength() : 0;
                          if (contentLength > 0) {
                              var BufferObj = Buffer.$new();
                              requestBody.writeTo(BufferObj);
                              try {
                                  console.log("\nrequest body String:\n", BufferObj.readString(), "\n");
                              } catch (error) {
                                  try {
                                      console.log("\nrequest body ByteString:\n", ByteString.of(BufferObj.readByteArray()).hex(), "\n");
                                  } catch (error) {
                                      console.log("error 1:", error);
                                  }
                              }
                          }
                      } catch (error) {
                          console.log("error 2:", error);
                      }
                      var response = chain.proceed(request);
                      try {
                          console.log("MyInterceptor.intercept onLeave:", response, "\nresponse headers:\n", response.headers());
                          var responseBody = response.body();
                          var contentLength = responseBody ? responseBody.contentLength() : 0;
                          if (contentLength > 0) {
                              console.log("\nresponsecontentLength:", contentLength, "responseBody:", responseBody, "\n");
     
                              var ContentType = response.headers().get("Content-Type");
                              console.log("ContentType:", ContentType);
                              if (ContentType.indexOf("video") == -1) {
                                  if (ContentType.indexOf("application") == 0) {
                                      var source = responseBody.source();
                                      if (ContentType.indexOf("application/zip") != 0) {
                                          try {
                                              console.log("\nresponse.body StringClass\n", source.readUtf8(), "\n");
                                          } catch (error) {
                                              try {
                                                  console.log("\nresponse.body ByteString\n", source.readByteString().hex(), "\n");
                                              } catch (error) {
                                                  console.log("error 4:", error);
                                              }
                                          }
                                      }
                                  }
     
                              }
     
                          }
     
                      } catch (error) {
                          console.log("error 3:", error);
                      }
                      return response;
                  }
              }
          });
          var ArrayList = Java.use("java.util.ArrayList");
          var OkHttpClient = Java.use("okhttp3.OkHttpClient");
          console.log(OkHttpClient);
          OkHttpClient.$init.overload('okhttp3.OkHttpClient$Builder').implementation = function (Builder) {
              console.log("OkHttpClient.$init:", this, Java.cast(Builder.interceptors(), ArrayList));
              this.$init(Builder);
          };
     
          var MyInterceptorObj = MyInterceptor.$new();
          var Builder = Java.use("okhttp3.OkHttpClient$Builder");
          console.log(Builder);
          Builder.build.implementation = function () {
              this.interceptors().clear();
              //var MyInterceptorObj = MyInterceptor.$new();
              this.interceptors().add(MyInterceptorObj);
              var result = this.build();
              return result;
          };
     
          Builder.addInterceptor.implementation = function (interceptor) {
              this.interceptors().clear();
              //var MyInterceptorObj = MyInterceptor.$new();
              this.interceptors().add(MyInterceptorObj);
              return this;
              //return this.addInterceptor(interceptor);
          };
          console.log("hook_okhttp3...");
      });

推荐拦截器

  1. 推荐 Frida 的 okhttp 成品拦截器
  2. okhttp 自带的拦截器 okhttp3logging 编译成 dex 后可以给Frida直接调用,简单粗暴(文章末尾可下载)
// 使用 okhttp3logging

function hook_okhttp3() {
    // 1. frida Hook java层的代码必须包裹在Java.perform中,Java.perform会将Hook Java相关API准备就绪。
    Java.perform(function () {

        Java.openClassFile("/data/local/tmp/okhttp3logging.dex").load();
        // 只修改了这一句,换句话说,只是使用不同的拦截器对象。
        var MyInterceptor = Java.use("com.roysue.octolesson2ok3.okhttp3Logging");

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

hook_okhttp3();

然后就可以在终端里用 adb logcat 查看日志了

资料下载

涵盖 Demo 代码, 成品 dex。回复可见

此处内容需要评论回复后(审核通过)方可阅读。

Last modification:November 9, 2020
如果觉得我的文章对你有用,请随意赞赏