Skip to main content

usb-rea — Reverse Engineer any USB gadget

ci license usb-rea MCP server

usb-rea demo: capture labelled clicks, get the protocol and a working driver

Got a USB device that only ships a Windows vendor app (case LCD, RGB controller, mouse, "smart" lamp)? Click around in the vendor app while usb-rea captures the USB traffic (usbmon on Linux, USBPcap on Windows), diffs the packets per action, infers the protocol, and writes an open-source Python/libusb driver — with every conclusion linked to the exact packets that prove it.

Status: alpha (v0.2.0). Validated on synthetic devices, on protocols documented by liquidctl and rivalcfg, and on public Wireshark captures — see docs/VALIDATION.md. Not yet tested on a physical gadget: your captures are welcome.

Try it in 10 seconds (no hardware needed)

pip install git+https://github.com/emirmrkaljevic/usb-rea
usb-rea demo --device fan
fan    100%  0x5a | counter (+1 per message) | 0x10 | u16be round(value * 1 + 0) | 0x00 | u16le crc16_modbus(bytes[0:6])
color  100%  0x5a | counter (+1 per message) | 0x20 | round(value * 1 + 0) | round(value[1] * 1 + 0) | round(value[2] * 1 + 0) | u16le crc16_modbus(bytes[0:6])
mode   100%  0x5a | counter (+1 per message) | 0x30 | lookup 1→0x11, 2→0x22, 3→0x47 | 0x00 | 0x00 | u16le crc16_modbus(bytes[0:6])

It writes a synthetic capture of a fan controller, recovers the protocol, and writes report.md (every claim linked to Wireshark frame numbers) and a working pyusb driver that encodes values it never saw.

--device lamp (default) is a simple 8-bit device; --device dial shows 32-bit values and packed bitfields:

position     100%  0xa5 | 0x01 | u32le round(value * 1 + 0) | sum8(bytes[0:6])
level        100%  0xa5 | 0x02 | bits[0:4] = round(value * 1 + 0) | 0x00 | sum8(bytes[0:4])

What it can infer

Role Example
constant header / command id 5a, 10 vs 20 vs 30
linear values, 8-, 16- or 32-bit LE/BE, several per action fan 2650 → 0a 5a; color 255 24 0; position 50000 → 50 c3 00 00
packed bitfields (bits beside constant flag bits, incl. 12-bit spans over two bytes) level 7 → b7 = flags b0 + bits[0:4]
lookup tables (non-linear choices) DPI 250→08, 500→07 …
rolling counters sequence byte +1 per message
checksums sum8, xor8, neg/inv sum8, sum16, CRC8, CRC8/MAXIM, CRC16 CCITT-FALSE/XMODEM/MODBUS/KERMIT

Linear fits must survive leave-one-out cross-checks; otherwise usb-rea falls back to an honest lookup table and says so.

Real device workflow (Linux)

sudo modprobe usbmon
usb-rea capture start -o lamp.pcapng
usb-rea mark -m lamp.pcapng.actions.json "brightness 0%"    # then click it in the vendor app
usb-rea mark -m lamp.pcapng.actions.json "brightness 50%"   # ...repeat for 3+ values per setting
usb-rea capture stop
usb-rea report lamp.pcapng -o report.md
usb-rea scaffold lamp.pcapng -o lamp_driver.py
usb-rea dissector lamp.pcapng -o lamp.lua      # Wireshark dissector for the same protocol

Captured on Windows with USBPcap/Wireshark and no markers? Click each action with a short pause in between, then just list them in order — usb-rea splits the traffic at the pauses:

usb-rea report lamp.pcapng --labels "brightness 0%; brightness 50%; brightness 100%; power off; power on"
usb-rea scaffold lamp.pcapng --labels labels.txt -o lamp_driver.py   # one label per line

(Markers, if you have them, are a JSON list of {"label", "start", "end"} epoch timestamps.)

MCP server

pip install "usb-rea[mcp] @ git+https://github.com/emirmrkaljevic/usb-rea" then add usb-rea mcp as a stdio server. Tools: capture_start, capture_stop, mark_action, diff_actions, report, scaffold_driver, hid_descriptor (decode a HID report descriptor / report payloads), wireshark_dissector, replay_packet (refuses unless the human confirmed). Analysis tools accept the same labels argument as the CLI for marker-free captures.

With uv no install step is needed:

{"mcpServers": {"usb-rea": {"command": "uvx", "args": ["--from", "usb-rea[mcp] @ git+https://github.com/emirmrkaljevic/usb-rea", "usb-rea", "mcp"]}}}

Once usb-rea is on PyPI, --from "usb-rea[mcp]" is enough. The server is also listed on Glama, which builds it from the repo's Dockerfile and checks that it starts and lists its tools.

How it works

  1. usb-rea capture start — record traffic (usbmon / USBPcap)
  2. usb-rea mark "brightness 50%" — label each action you take in the vendor app
  3. usb-rea diff — which bytes change per action, value correlation, checksums, counters
  4. usb-rea infer — message templates + evidence report
  5. usb-rea scaffold — generate a pyusb driver and replay tests
  6. usb-rea dissector — write a Wireshark Lua dissector for the inferred protocol
  7. usb-rea replay — send packets to the device (only with explicit confirmation)
  8. usb-rea hid — decode a HID report descriptor from a capture (GET_DESCRIPTOR 0x22) or from hex, and decode report payloads
  9. usb-rea mcp — the same tools as an MCP server for AI agents

Wireshark dissector

usb-rea dissector capture.pcapng -o lamp.lua turns the inferred protocol into a Wireshark Lua plugin, so you can keep capturing and read the traffic as commands instead of hex:

wireshark -X lua_script:lamp.lua capture.pcapng
tshark -X lua_script:lamp.lua -r capture.pcapng -Y 'usbrea.command == "brightness"'

Each matching packet gets a usbrea tree with the command name, decoded values (usbrea.brightness.value), counters, lookup labels, and a checksum check (usbrea.checksum_ok, with an expert warning on mismatch); the Info column reads brightness 50. It works for bulk, interrupt and control/HID SET_REPORT transfers, from usbmon or USBPcap, and needs no bit library (Wireshark 3.x and 4.x). -n NAME changes the filter prefix. CI runs every generated dissector through tshark.

HID devices

Most RGB keyboards, mice, headsets and LCD gadgets are HID with a vendor-defined page. If the capture includes the report descriptor (start capturing, then replug the device), the report gets a section with every report's ID, size and fields, and each inferred command is tagged with the HID report it travels in. Without a capture:

usb-rea hid /sys/class/hidraw/hidraw0/device/report_descriptor --items
usb-rea hid capture.pcapng --decode "10ff0d1d000000" --type Output

Roadmap

  • pcap/pcapng parser (usbmon + USBPcap)
  • action markers and per-action diffing
  • checksum detection (sum8, xor8, neg/inv sum8, CRC8, CRC16 variants)
  • evidence-backed protocol report
  • driver scaffolding (pyusb, bulk/interrupt + control/HID SET_REPORT)
  • confirmed replay
  • MCP server
  • rolling counters, multi-byte (16/32-bit LE/BE) values, lookup tables, multi-value actions
  • packed bitfields
  • validation against documented protocols (liquidctl, rivalcfg)
  • HID report descriptor decoding (usb-rea hid), with captured commands mapped to their HID reports
  • emulated-device CI (dummy_hcd + configfs HID; script in scripts/gadget_e2e.sh)
  • real-hardware case studies
  • multi-packet transactions (write + apply), including checksums over earlier packets
  • state machines (request/response handshakes)

Reverse engineering for interoperability is permitted (EU Directive 2009/24/EC Art. 6, US DMCA §1201(f)). usb-rea only analyzes traffic of devices you own and never redistributes vendor code.

License

MIT

Metadata

Release files for usb-rea 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for usb-rea 0.2.1
File Size Uploaded
usb_rea-0.2.1.tar.gz 378.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for usb-rea 0.2.1
File Interpreter ABI Platform
usb_rea-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 421.0 kB

Release files / usb_rea-0.2.1.tar.gz

Download URL usb_rea-0.2.1.tar.gz
Size 378.7 kB
Tags Source
SHA-256 checksum
How to use checksums
6cafcac327eeda4f98746e1b9de6a849e9165e3c308d49b801a8da132a2e9946
BLAKE2b-256 checksum
How to use checksums
27dab28bebc1831f594f41d960ab7e85bb41e906986f9e712d35877510760f14
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / usb_rea-0.2.1-py3-none-any.whl

Download URL usb_rea-0.2.1-py3-none-any.whl
Size 42.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6b21992d1fa9266c8f75c98119e0d88ce5ba1c6712bd1cc2c3eb95239d64d03d
BLAKE2b-256 checksum
How to use checksums
b765d3435d32d30dde7b4c75a316ef79a2c566484aa7df173ee7607688727a39
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page