Building a Custom Drone Controller from Scratch — Part 2: Reverse Engineering the UDP Protocol

In Part 1 we introduced the project: a custom WiFi flight controller for Eachine E88/E58 toy drones running on an M5Stack AtomS3. But before writing a single line of firmware, there was a much bigger problem to solve — nobody publishes the protocol these drones speak. No SDK, no documentation, no public spec. If you want to control one of these drones from your own hardware, you have to figure out the protocol yourself.

This is the story of how that happened — entirely through packet capture analysis.

The Tool: PCAPdroid

The drone exposes its own WiFi access point. Its official Android app — the kind of generic white-label app that ships with these E88/E58 clones, often named something like WIFI_CAM or KY UFO — connects to that access point and talks to the drone over plain UDP, no encryption, no authentication. That makes it a perfect target for packet capture.

Using PCAPdroid (a packet capture app for Android that doesn’t require root), it’s possible to record every packet exchanged between the phone and the drone while flying it normally with the official app. The result is a .pcap file that can be opened in Wireshark for analysis.

This single technique — capture with the phone, analyze with Wireshark — was enough to fully reverse-engineer two completely different drone protocols, described below and in Part 6 of this series.

Step 1: Finding the Control Channel

The first question is always: which port is the drone listening on? Standard E58/E88 drones are documented (informally, around hobbyist forums) to use UDP port 50000 or 7099. A quick port scan against this drone showed those ports closed. The actual control channel turned out to be UDP port 8090 — non-standard, and only discoverable by capturing real traffic from the official app.

Filtering the capture by the drone’s IP address (192.168.4.153) and watching for periodic, fixed-size UDP packets immediately revealed the pattern: 8-byte packets sent roughly 25 times per second while the joystick was active.

Step 2: Decoding the Packet Format

Looking at several consecutive packets side by side made the structure obvious almost immediately — most bytes stayed at a constant value (0x80, the “neutral” position for a joystick axis), while one byte changed smoothly as the throttle stick moved:

66 80 80 80 80 00 00 99   ← all axes neutral
66 80 80 26 80 00 a6 99   ← throttle increasing
66 80 80 52 80 00 d2 99   ← throttle higher

From this, the 8-byte structure became clear:

[ 0x66 | Roll | Pitch | Throttle | Yaw | Cmd | XOR | 0x99 ]
  • Byte 0 — fixed header 0x66
  • Bytes 1–4 — Roll, Pitch, Throttle, Yaw, each centered at 0x80 (128)
  • Byte 5 — command flags (take-off, land, flip, etc.)
  • Byte 6 — checksum
  • Byte 7 — fixed footer 0x99

The checksum was the easiest part to confirm — byte 6 is simply the XOR of the four axis bytes. Take the second sample above: 0x80 ^ 0x80 ^ 0x26 ^ 0x80 = 0xA6. Matches exactly.

Step 3: The Missing Piece — App Mode Activation

Here’s where things got interesting. Sending these exact 8-byte packets to port 8090 did nothing. The drone simply ignored them.

The capture held the answer. Right after connecting, before any control packet appeared on port 8090, the app sent two tiny packets to a completely different port — UDP 8080, which is also the drone’s video streaming port:

42 76   → sent on connect: switches drone to WiFi/app control mode
42 77   → sent on disconnect: returns drone to 2.4 GHz RF controller mode

The drone normally boots in 2.4 GHz RF mode (controlled by its physical remote) and completely ignores WiFi commands until this two-byte handshake arrives. Once 42 76 is sent, the drone switches modes, the video stream starts instantly, and port 8090 starts accepting control packets. This single discovery — a two-byte “magic packet” hidden in the connection sequence — was the missing 10% that made the whole protocol work.

Step 4: The Keepalive Packet

One more detail surfaced while analyzing idle periods in the capture — moments where the joystick wasn’t being touched. Instead of going silent, the app kept sending a different 8-byte packet roughly every 790 ms:

AA 80 80 00 80 00 80 55

Notice the header and footer: 0xAA and 0x55 are the bitwise complements of 0x66 and 0x99 — a nice touch of symmetry from whoever designed this protocol. This keepalive almost certainly prevents the drone from timing out the connection and triggering a failsafe landing.

Step 5: Mapping the Command Flags

The command byte (byte 5) only changes when the user presses a button in the app — take off, land, flip, calibrate, etc. By isolating captures around each button press and comparing the command byte before and after, each flag could be matched to its function:

BitValueFunction
00x01Auto take-off
10x02Land
20x04Emergency stop
30x08360° flip
40x10Headless mode
50x20Lock
60x40Unlock motors
70x80Calibrate gyro

The Complete Picture

Putting it all together, the full control sequence for this drone (which we identified as a WIFI_8K_ variant — confirmed via its SSID WIFI_8K_Wf48702) looks like this:

  1. Connect to the drone’s WiFi access point
  2. Send 42 76 to UDP port 8080 — switches the drone into app control mode
  3. Send 8-byte control packets to UDP port 8090 at ~25 Hz while flying
  4. Send the AA…55 keepalive every ~790 ms when the stick is idle
  5. Send 42 77 to UDP port 8080 on disconnect — returns the drone to RF mode

None of this is documented anywhere. It was all extracted, byte by byte, from real traffic captured between a phone and a drone.

Why This Matters

This kind of analysis isn’t just useful for toy drones. The same workflow — capture real traffic, isolate patterns, correlate user actions with byte changes — applies to any closed proprietary protocol: IoT devices, smart home gadgets, obscure consumer electronics. PCAPdroid plus Wireshark plus patience is a surprisingly powerful combination.

The full implementation of this protocol, including the packet encoder, checksum logic, and state machine that drives it, lives in the project’s source code: github.com/popolony2k/maritaca-e88-controller.

What’s Next

In Part 3, we’ll move from protocol to firmware — the architecture decisions behind the AtomS3 codebase: the hardware abstraction layer, the non-blocking control loop, and the flight state machine that turns raw protocol bytes into a real, controllable drone.

Enjoy
[]’s
PopolonY2k