As we were capable of reconstructing the CRC target and XOR parameters last time for the connection handshake, we will re-review the 0x21 packet and try to apply the same strategy. Maybe there are some CRC values hidden behind the bytes which we weren’t able to categorize.
0x07 seems to be a CRC checksum of the 0x04 counter, as we can predict future values by applying following formula: 0x04 XOR 0xCA = 0x07. (See Fig. 1) However, compared to yet another recording scenario, the right-side XOR parameter doesn’t equal 0xCA, but 0xE2. (See Fig. 2) Therefore, the operator somehow requires to obtain that arbitrary but fixed number based on existing information. What the drone and the operator agreed on are following hex numbers: 0x6c / 0x21 / 0x60 / 0xBF / 0xFD / 0xC5 whereas the last two are checksums within the handshake. More information isn’t available. Consequently the origin of the 0xE2 needs to be extracted from one (or several) of those numbers, as the bit sequence for 0xE2 isn’t present anywhere within the 0x21, and any previous, packet.
Long story short: We weren’t able to extract the XOR value predictively with the previously mentioned pre-shared values and came to the final conclusion, that hidden within the APK and FW a static HEX table must exist for multiple XOR operations. Hence, guessing and bruteforcing won’t lead to any useful result. This finding introduced a new branch within our reverse-engineering process: Searching for a published FW or APK source-code, in order to obtain the desired HEX tables.
We came across the OGs (Original Gangsters) repository which not only offers tools to facilitate the reverse-engineering process, but also a large, in-depth knowledge base about Dji’s communication protocol of various drones. As an example, they provide packet descriptors to translate raw bytes into a human readable format. (See Fig. 3)
OG’s packet descriptors
The Dji’s communication protocol, despite the communication channel (Serial, Bluetooth, Wifi, SDR), share a single protocol base; the so called DUML stream. This DUML stream (E.g.: See Fig 1. 0x14 – 0x20) will be wrapped, depending on the communication channel, into yet another protocol header (E.g.: See Fig 1. 0x00 – 0x13). We do have a packet, inside a packet, inside a packet, inside a packet, inside yet another packet; type of situation here. But let’s go through it step by step.
|As the operator and the drone communicate via UDP, the first header we approach is the UDP packet structure itself; with a length of 42 Bytes.|
|The Wifi Header features values such as Payload-length, Session identifier and some kind of packet-counters. However, the actual length varies and the purpose of most bytes haven’t been reasoned yet.|
|A valid packet between the two participants start with the DUML Header, indicated by a magic number. (In case of the Dji Mavic Pro: 0x55) The header includes the magic-number (called the delimiter), Size of the following body, the protocol version and a CRC checksum.|
|Regardless of the sent command, the body features information about the Sender and Receiver, the command– and encryption-type as well as a CRC value; covering not only the DUML Body, but also the DUML Tail.|
|Depending on the command-type, the tail contains n Bytes representing the command’s payload.|
The DUML stream covers the DUML Header up to the DUML Tail, as this protocol is consistent throughout all transmission-types. The UDP Data and Wifi-Header is, based on our research strategy, proprietary to the wireless communication. As we haven’t yet analysed the header for Serial, Bluetooth nor SDR transmission-types yet, we have to assume that those headers might differ. Nevertheless, back to the topic – the OG’s packet descriptors. Their descriptors (called dissectors) will describe each and every bit within the DUML protocol (E.g.: See Fig. 3).
And this, ladies and gentleman, is the holy grail. With the provided dissectors we can fully understand and analyse the whole wireless communication between the operator and the drone. They only thing left to do is: converting a UDP packet and its payload into a valid DUML packet. Awesome as the OG’s are, they did provide a python script to convert a hex stream into a valid DUML packet. However, as the whole situation has changed, we decided to integrate not only the dissectors (See Fig. 4), but also the DUML packet conversion into our application. With that said, the application now includes:
- Live-Conversion from a UDP packet into a DUML packet
- Live DUML Body inspection
- Export UDP packet-captures as DUML packets
Upon recording, the application will create two independent *.pcap files. The first includes the raw UDP communication between both participants and the second one contains only valid DUML packets, ready for the Wireshark dissectors. This allows us to start a simulation based on the original UDP communication and to investigate DUML packets on-the-fly. The application is far from being complete and is lacking a lot features we plan to build in, but we decided to publish it on GitHub already, since the most important bits are based on the OG’s provided knowledge.
The DUML dissectors didn’t solve our original problem, but we gained in-depth knowledge about the actual packet structure and its content. Our first introduced issue with the CRC value at 0x07 is located within the Wifi-Header and thus, out of scope of the DUML dissector. Time will tell whether we can reuse DUML based CRC checks on the Wifi-Header as well, but that’s something for the future Thomas.