Ctrip travel app data collection

Ctrip travel app data collection

Goal: Collect hotel room prices and hotel static data on Ctrip travel app through agreement

jadx decompilation

Insert image description here

Packet capture analysis

Through Charles or FD, it is found that the packet cannot be captured normally. Through the wireshark packet capture, it is found that a private protocol based on TCP is used.

After extensive analysis, it was concluded that SOTPConnection is responsible for communication requests.


private boolean sendRequest(j jVar) throws Exception {
    
    
        if (ASMUtils.getInterface("b009009091d7678cf389322a73af7974", 5) != null) {
    
    
            return ((Boolean) ASMUtils.getInterface("b009009091d7678cf389322a73af7974", 5).accessFunc(5, new Object[]{
    
    jVar}, this)).booleanValue();
        }
        long currentTimeMillis = System.currentTimeMillis();
        try {
    
    
            jVar.b(jVar.G() + 1);
            jVar.a.add("4");
            Executors.buildRequest(jVar);
            currentTimeMillis = System.currentTimeMillis();
            if (checkTaskCancel(jVar)) {
    
    
                finishTask(jVar);
            }
            if (jVar.K()) {
    
    
                if (this.socket != null) {
    
    
                    byte[] y = jVar.y();
                    OutputStream outputStream = this.socket.getOutputStream();
                    outputStream.write(y);
                    outputStream.flush();
                    jVar.a.add(Constants.VIA_REPORT_TYPE_SHARE_TO_QZONE);
                    jVar.j(System.currentTimeMillis());
                    jVar.e(System.currentTimeMillis() - currentTimeMillis);
                    jVar.l(System.currentTimeMillis());
                    return true;
                }
            }
            jVar.j(System.currentTimeMillis());
            jVar.e(System.currentTimeMillis() - currentTimeMillis);
            jVar.l(System.currentTimeMillis());
            return false;
        } catch (Exception e) {
    
    
            throw e;
        } catch (Throwable th) {
    
    
            jVar.j(System.currentTimeMillis());
            jVar.e(System.currentTimeMillis() - currentTimeMillis);
            jVar.l(System.currentTimeMillis());
        }
    }

Use a custom packet capture tool to obtain request and response data packets from here.

Request and response decoding

Through debugging analysis, we learned that ProtocolHandle is responsible for serialization and deserialization, and the specific reverse process is not detailed.
Different sections have different serialization methods. The following class defines the serialization method involved in the entire app.

public enum CommEncodingType {
    
    
    None,
    Normal,
    UTF8,
    PB,
    Json,
    SotpPB,
    SotpJson,
    PBSotp,
    PBJson,
    JsonSotp,
    JsonPB,
    GraphQL
}

The overall communication protocol is relatively complex, involving Gzip compression, AES encryption and custom request headers, which requires a lot of time and energy to restore.

Encryption and decryption reverse analysis

The encryption and decryption involved are implemented in EncodeUtil.

    public native byte[] cd(byte[] bArr, int i);

    public native byte[] ce(byte[] bArr, int i);

It is implemented by local method, through the following code

static {
    
    
        try {
    
    
            System.loadLibrary("ctripenc");
        } catch (Throwable th) {
    
    
            if (!classVerify) {
    
    
                th.printStackTrace();
                System.loadLibrary("ctripenc");
            }
        }
    }

It can be seen that it is implemented in the ctripenc so file. You can see it by opening lib/armeabi

Insert image description here
The cd and ce methods need to be restored.

Write client test

 public static void testHotelRoomListRequest(int hotelID, String checkInDate, String checkOutDate) throws Exception {
    
    
        RequestDataBean requestDataBean = buildHotelRoomListRequest(hotelID,checkInDate,checkOutDate);
        byte[] totalData = requestDataBean.totelData;
        byte[] responseBodyData = send2ctrip(totalData);
        HotelRoomListResponse hotelRoomListResponse = new HotelRoomListResponse();
        ProtobufIOUtil.mergeFrom(responseBodyData, hotelRoomListResponse, HotelRoomListResponse.getSchema());
        System.out.println(JSON.toJSONString(hotelRoomListResponse));
    }

Write a main method and execute it to get the price list.

Insert image description here

The json content of the price list is relatively large. The price part is excerpted below for display.

"priceInfoList": [
        {
    
    
          "avgPrice": "224",
          "avgPriceAfterDiscount": "224",
          "avgPriceAfterDiscountIncludeTax": "224",
          "avgPriceIncludeTax": "224",
          "avgTax": "0",
          "cashBackAvgAmount": "0",
          "cashBackTotalAmount": "0",
          "currencyCode": "RMB",
          "primeDiscount": "0",
          "totalDays": 1,
          "totalPrice": "224",
          "totalPriceAfterDiscount": "224",
          "totalPriceAfterDiscountIncludeTax": "224",
          "totalPriceIncludeTax": "224",
          "totalTax": "0"
        }
      ]

Guess you like

Origin blog.csdn.net/super19911115/article/details/120049453