frida-okhttp3-intercept

by
4 views 8753316c...

Description

Intercepts OkHttp3 requests and prints the requests.

How to Use

Download the script and run it with Frida CLI:

Download Script

Then run with Frida:

frida -U -f YOUR_PACKAGE_NAME -l frida-okhttp3-intercept.js

Replace YOUR_PACKAGE_NAME with the target app's package name.

Source Code

JavaScript
// @RadonCoding
// 20/04/2025

Java.perform(function () {
  Java.use("okhttp3.OkHttpClient");
  const RequestBody = Java.use("okhttp3.RequestBody");
  const Charset = Java.use("java.nio.charset.Charset");

  const ByteArrayInputStream = Java.use("java.io.ByteArrayInputStream");
  const GZIPInputStream = Java.use("java.util.zip.GZIPInputStream");
  const InputStreamReader = Java.use("java.io.InputStreamReader");
  const BufferedReader = Java.use("java.io.BufferedReader");
  const StringBuilder = Java.use("java.lang.StringBuilder");

  const String = Java.use("java.lang.String");

  function gunzip(bytes) {
    const byteArrayInputStream = ByteArrayInputStream.$new(bytes);
    const gzipInputStream = GZIPInputStream.$new(byteArrayInputStream);
    const reader = BufferedReader.$new(
      InputStreamReader.$new(gzipInputStream, Charset.forName("UTF-8"))
    );

    const sb = StringBuilder.$new();

    let line;

    while ((line = reader.readLine()) !== null) {
      sb.append(line);
    }
    return sb.toString();
  }

  let Buffer;

  const RequestBodyMethods = RequestBody.class.getDeclaredMethods();

  let BufferedSink = null;

  for (let i = 0; i < RequestBodyMethods.length; i++) {
    const method = RequestBodyMethods[i];

    if (method.getName() === "writeTo") {
      const paramTypes = method.getParameterTypes();

      if (paramTypes.length === 1) {
        BufferedSink = paramTypes[0].getName();
        break;
      }
    }
  }

  if (!BufferedSink) {
    console.error("[!] Could not find obfuscated name for okio.BufferedSink.");
    return;
  }

  console.log(
    `[+] Found obfuscated name for okio.BufferedSink: ${BufferedSink}`
  );

  Java.enumerateLoadedClasses({
    onMatch: function (className) {
      if (Buffer) return;

      if (!className.startsWith("okio.")) return;

      const clazz = Java.use(className);

      const interfaces = clazz.class.getInterfaces();

      for (let i = 0; i < interfaces.length; i++) {
        if (interfaces[i].getName() === BufferedSink) {
          Buffer = clazz;
          break;
        }
      }
    },
    onComplete: function () {},
  });

  if (!Buffer) {
    console.error("[!] Could not find okio.Buffer.");
    return;
  }

  console.log(`[+] Found okio.Buffer: ${Buffer}`);

  const BufferMethods = Buffer.class.getDeclaredMethods();

  let readByteArray;

  for (let i = 0; i < BufferMethods.length; i++) {
    const method = BufferMethods[i];
    const paramTypes = method.getParameterTypes();
    const returnType = method.getReturnType();

    if (paramTypes.length === 0 && returnType.getName() === "[B") {
      readByteArray = method;
      break;
    }
  }

  if (!readByteArray) {
    console.error("[!] Could not find okio.Buffer::readByteArray.");
    return;
  }

  console.log(`[+] Found okio.Buffer::readByteArray: ${readByteArray}`);

  const RealCall = Java.use("okhttp3.internal.connection.RealCall");

  const originalExecute = RealCall.execute;

  RealCall.execute.implementation = function () {
    const response = originalExecute.call(this);

    try {
      const log = [];

      const request = response.request();

      const method = request.method();
      const url = request.url().toString();
      log.push(`[Intercepted] ${method} ${url}`);

      log.push("[Intercepted] Request Headers:");

      const requestHeaders = request.headers();

      for (let i = 0; i < requestHeaders.size(); i++) {
        log.push(`    ${requestHeaders.name(i)}: ${requestHeaders.value(i)}`);
      }

      const requestBody = request.body();

      if (requestBody) {
        log.push("[Intercepted] Request Body:");

        const buffer = Buffer.$new();
        requestBody.writeTo(buffer);

        const bytes = Java.array("byte", readByteArray.invoke(buffer, []));

        let body;

        const encoding = request.header("Content-Encoding");

        if (encoding === "gzip") {
          body = gunzip(bytes);
        } else {
          body = String.$new(bytes);
        }

        log.push(`    ${body}`);
      }

      console.log(log.join("\n"));
    } catch (err) {
      console.error("Error while intercepting:", err.toString(), err.stack);
    } finally {
      return response;
    }
  };
});
Share this script:
Twitter LinkedIn

Comments

Login or Sign up to leave a comment.
Loading comments...