Analysis of OkHttp general packet capture method, taking a small video app as an example

1. Goals

It is too difficult. It is getting more and more difficult to capture packets these years. A small video is updated frequently. Our previous plan to block QUIC seems to have failed.

Luckily we still have OkHttpLogger - Frida

TYPE: v9.10.10.22596

Students who are in a hurry can pull to the back and join Knowledge Planet to get js. Students with ideals are suggested to study the principles carefully, so that they can adapt themselves next time.

Two, steps

Principle analysis

In A Small Video App v8.x Signature Calculation Method (1) Let’s start with packet capture In this article, we analyzed the method of v8.0 using OkHttpLogger-Frida to capture packets.

So what type of App is suitable for capturing packets with OkHttpLogger-Frida?

The author describes the principle: Since all the requests sent by the App using the Okhttp framework are sent through RealCall.java, then we can hook this class to get the request and response.

We open the apk with jadx

main.png

To put it simply, for any app that obviously finds Okhttp, there is a high probability that this script can be used to capture packets. If Okhttp is not obviously found, it may be confused. You can run the find command of this script to try to find it .

analyse problem

Some friends will say, I tried this script, but it doesn't work, and I can't catch the package.

The big guys are all throwing bricks to attract jade, and no one will go to the pains to help you adapt to each version. So we need to comprehend the principle of the script to do the adaptation ourselves.

First copy okhttpfind.dex to /data/local/tmp/

Then frida -U -l okhttp_poker.js -f com.example.demo --no-pause ran.

First run the find() command. From the printed results, we can see that this App uses okhttp3 , and then write down the output of this line.

var Cls_okio_Buffer = "okio.f";

Now you can start capturing packets, type the hold() command

Beautiful, it is already possible to output url and Request Headers information.

There are two problems here:

1. If the Request Body is not printed out, it prompts a "File Request Body Omit..."

2. The Response data is not printed out.

3. There is such an error

print request error :  Error: writeTo(): argument types do not match any of:
	.overload('okio.g')
    at X (frida/node_modules/frida-java-bridge/lib/class-factory.js:563)
    at value (frida/node_modules/frida-java-bridge/lib/class-factory.js:966)
    at e (frida/node_modules/frida-java-bridge/lib/class-factory.js:547)
    at printerRequest (/okhttp_poker.js:171)
    at printAll (/okhttp_poker.js:106)
    at <anonymous> (/okhttp_poker.js:89)
    at <anonymous> (frida/node_modules/frida-java-bridge/lib/vm.js:16)
    at perform (frida/node_modules/frida-java-bridge/index.js:193)
    at buildNewResponse (/okhttp_poker.js:98)
    at <anonymous> (/okhttp_poker.js:510)
    at apply (native)
    at ne (frida/node_modules/frida-java-bridge/lib/class-factory.js:613)
    at <anonymous> (frida/node_modules/frida-java-bridge/lib/class-factory.js:592)

adaptation code

Look at the first question first. There is a filterUrl judgment in line okhttp_poker.js:160. The original intention is to filter out image files, but if the request value or return value contains strings such as "jpg" and "png" will be filtered out, so we need to judge accurately, and filter only when the last few strings match.

var filterArray = [".JPG", ".jpg", ".PNG", ".png", ".WEBP", ".webp", ".JPEG", ".jpeg", ".GIF", ".gif",".zip", ".data"]
......

/**
 *  fenfei 过滤url
 *  false 显示
 *  true  拦截 不显示 返回信息
 */
function filterUrl(url) {
	
	//*
    for (var i = 0; i < filterArray.length; i++) {
        // if (url.indexOf(filterArray[i]) != -1) {
            // console.log(url + " ?? " + filterArray[i])
        //    return true;
        //}

        if (url.lastIndexOf(filterArray[i]) >= (url.length - 6) ) {
           // console.log(url + " ?? " + filterArray[i])
           return true;
        }
		
    }
	// */
	
    return false;
}

The reason for the second problem is not clear for the time being, so let's solve the error report first.

There is the following code in at printerRequest (/okhttp_poker.js:171)

        var buffer = BufferWapper.$new()
        requestBody[M_reqbody_writeTo](buffer)

It means to writeTo the value of requestBody into the buffer variable of type BufferWapper.

BufferWapper type is ** var Cls_okio_Buffer = "com.singleman.okio.Buffer"; **

This solution already has two hints:

1. The error message reminds us that we need an okio.g type here

2. When we find at the beginning, we are prompted to var Cls_okio_Buffer = “okio.f” in this app;

So should I use okio.g or okio.f?

Let's look at the code analyzed by jadx

public interface g extends z, WritableByteChannel {
......
}

public final class f implements h, g, Cloneable, ByteChannel {
......
}

okio.g is an interface class, and okio.f is the implementation class that inherits it. So there is no doubt to use #okio.f#

modify it like this

// add fenfei 适配 910
// var buffer = BufferWapper.$new()

var ffBufferWapper = Java.use("okio.f");
var buffer = ffBufferWapper.$new();

Run it again, this time it is very beautiful, both Request and Response are printed out.

last question

After adding this packet capture, the app suddenly became very unstable, either stuck for a while, or failed to access the network.

This problem must be caused by our js. But what exactly caused it? How to troubleshoot the problem?

The best way to solve this kind of problem is the method of elimination .

1. Block the printAll function, nothing will be printed, and the app runs Ok, indicating that the hook is ok, and the problem lies in the printing.

2. Printing is divided into two parts, printerRequest and printerResponse. Through the shielding method, it is found that the problem lies in printerResponse.

3. Continue to use the shielding method in the printerResponse function, and find that the problem lies in the buffer[M_buffer_readByteArray] in the getByteString function, that is to say, as long as the Response body is read, there will be a problem.

At present, I feel that the problem may lie in the reading of the buffer. It may be a reading conflict. Because our hook script reads this buffer, the app cannot read the result, so various weird problems occur.

Then I tried various methods, such as changing the reading function and deep copying the buffer, but none of them succeeded. In the end, it was found that the author had reserved one hand. In fact, the author had made a deep copy of the Response body and generated a newResponse.

So we continue to hook ours, happily print it out, and then return the generated newResponse to the app and it's ok.

Run it again and call it a day.

3. Summary

Although the use of doctrine is easy to use, it is more important to be able to adapt after understanding the principle.

When encountering a problem, first follow the principle of minimum availability and block the code step by step to narrow the scope and define the problem.

ffshow.jpeg

As long as you think of the things you regret in your life, plum blossoms will fall all over Nanshan

Guess you like

Origin blog.csdn.net/fenfei331/article/details/122661732