preface

Nowadays, there are many live broadcast protocols that rarely use HTTP polling to get live broadcast bullets, gifts, attention and so on. Currently, what we know is the live broadcast of a certain tone. Some other apps have used socket or websoceket to get live broadcast bullets and so on. This paper mainly provides the idea of protocol cracking for Websocket. Device: Mi Note8, Windows case: specific not to provide, only to provide cracking ideas.

Caught analysis

This packet capture uses Charles to capture websocket. Charles configuration is simple and packet capture is convenient.Open the live broadcast room of the app, and you can clearly see the data sent by websocket and the push information received in Charles.

ws://chat.**.com:3185
Copy the code

Ws :// is the obvious feature of the websocket. In addition to ws://, WSS :// is the encrypted version of WS, similar to the relationship between HTTP and HTTPS.

Dehulling analysis and positioning

This app is through packer, youpk here used for hulling, specific processes can see a lot, github.com/Youlor/Youp…

Locating key locations

By capturing the keyword of the packetctor.entryHandler.enterLocation in the app.So this SDK tells us all about it,com.netease.pomelo, through the relevant information

Pomelo is a Node.js-based game server framework produced by netease at the end of 2012. It was originally designed as a game server, but after the completion of design and development, it was found that Pomelo is a universal distributed real-time application development framework.Copy the code

According to netease Github,Github.com/netease/pom…Relevant information, its usesocket.ioThe packet is sent, and the log of sending data can be clearly seen in logcat.However, if garbled characters are directly found in the packet, you can only look for the original bytes of the packet. Further hook analysis was performed to locate the location as shown below. Hook print class via Frida, called by defaulttostringmethods

 var FramedataImpl1 = Java.use("org.java_websocket.framing.FramedataImpl1")
    FramedataImpl1.b.overload('boolean').implementation = function (q1) {
        this.b(q1)
        console.log(this)
    }
Copy the code

The result is the following byte array

/ / 51, 58, 58, 58, 0, 0, 0, 1, 31, / / 51, 58, 58, 58, 0, 0, 0, 2, 28, / / 51, 58, 58, 58, 0, 0, 0, 3, 35, / / 51, 58, 58, 58, 0, 0, 0, 4, 32, / / 51, 58, 58, 58, 0, 0, 0, 5, 32, / / 50, 58, 58Copy the code

The rest is to discover the pattern, the order of packets and which packets to send, where 51, 58, 58, 58, is 3::,50, 58, 58 is 2::, and the garbled characters, which are the corresponding bytes in the second half, include the order of packets to send, from 0 to 9 and so on.

Reduction agreement

Using the pythonwebsocket-clientFor protocol communication in the restore direct broadcast room. The above bytes can be encoded using Base64 in Java and then decoded for use in Python.


def send_msg(ws):
    a = base64.b64decode('Mzo6OgAAAAEf')
    enter = {"sid": "", "rid": str(room_id), "userid": "0",
             "brand": "Redmi Note 8", "cores": 8, "memory": 5638, "screen": 1080, "trid": 666, "re_enter": 1,
             "true_ip": "210*12*195*3", "sktime": 1622114102, "sign": sign,
             "version_code": 507,
             "is_intl_pack": "0", "channel": "9700288", "client_code_version": "23", "client_side": 2, "sys_sdk": 29,
             "country_code": "CN", "pkg_channel": "9700288", "is_market": "1", "timestamp": 1622114101589}
    ws.send(a + bytes('sioconnector.entryHandler.enter' + json.dumps(enter), encoding='utf8'))
    b = base64.b64decode('Mzo6OgAAAAIc')
    ws.send(b + bytes('chat.chatHandler.getTopThree' + json.dumps({"timestamp": 1622113988470}), encoding='utf8'))
    c = base64.b64decode('Mzo6OgAAAAMj')
    ws.send(c + bytes('chat.chatHandler.checkUserStatusMix' + json.dumps({"uid": "0", "timestamp": 1622113988484}),
                      encoding='utf8'))
    d = base64.b64decode('Mzo6OgAAAAQg')
    ws.send(d + bytes('chat.chatHandler.getAnchorCdnMix' + json.dumps({"timestamp": 1622113988496}),
                      encoding='utf8'))
    e = base64.b64decode('Mzo6OgAAAAcg')
    ws.send(e + bytes('chat.chatHandler.getGuardinfo' + json.dumps({"timestamp": 1622113988496}),
                      encoding='utf8'))
    f = base64.b64decode('Mzo6OgAAAAYd')
    ws.send(f + bytes('chat.chatHandler.onlineGoldPhone' + json.dumps({"timestamp": 1622113988496}),
                      encoding='utf8'))
    while 1:
        ws.send(b'2::')
        sleep(1)


def on_open(ws):
    print('on_open', ws)
    threading.Thread(target=send_msg, args=(ws,)).start()


def on_message(ws, message):
    print(message)
    message = message[len('3:::'):]
    print('on_message', message)


def on_close(ws, close_status_code, close_reason):
    print('on_close', ws, close_status_code, close_reason)


def start_websocket(chat_url, token):
    # websocket.enableTrace(True)
    ws = websocket.WebSocketApp(
        f"ws://{chat_url}/socket.io/1/websocket/{token}",
        on_message=on_message,
        on_open=on_open,
        on_close=on_close
    )
    ws.run_forever()
Copy the code

summary

In the process of acquiring bullet screen, part of the data is in the form of garbled code in the live broadcast protocol of this live broadcast app. Hook can be used to get the data sent in the form of bytes. By comparing the difference of sent bytes, the data sent can be constructed and the protocol restoration can be completed at last.