Sniffing USB with Cynthion on a DP100

last updated: 2025-05-10

Intro

Mid 2021 I backed the promising Luna hardware from Great Scott Gadgets to sniff USB data on crowd supply. In february 2023 Luna hardware was renamed to Cynthion and my Cynthion was shipped mid 2024. I will use Cynthion here as USB 2.0 protocol analyzer (Low, Full, and High Speed).

Hardware to analyze: ALIENTEC DP100

The DP100 is a tiny power supply with 2 USB connectors. The USB-C connector is the power input up to 32 V, 5 A with an USB-PD power supply (or another DC alimentation up to 32 V). It has a tiny OLED display, three buttons and an adjustment wheel.

The second USB-A connector can also be used to provide power (5 V/1 A) but is primarily needed to connect the device to a PC and to use the PC Windows software. I don't use Windows, and I think that the provided software is not intuitive. Also the display is overloaded and it is not very intuitive to use the device. So perhaps we can change this with another software. To do so we need to understand the proprietary protocol used on USB.

So let's start :).

Setting up the Cynthion hardware

First we clone the repository to our favourite folder:

    git clone https://github.com/greatscottgadgets/cynthion.git

There is a good documentation on readthedocs: https://cynthion.readthedocs.io/en/latest/. So let's concentrate on the essential.

Connect the Cynthion device with the host control computer (running the software, man in the middle). Use the USB-C socket labelled CONTROL.

To avoid doing everything as root, we copy the udev rules to /etc/udev/rules.d, reload the rules and apply them to the devices already plugged in:

    cd cynthion
    sudo cp cynthion/python/assets/54-cynthion.rules /etc/udev/rules.d
    sudo udevadm control --reload
    sudo udevadm trigger

The Cynthion software is written in Python. So we use a virtual environment to deploy it. More on virtual environments: https://www.weigu.lu/other_projects/python_coding/using_venv/index.html.

    python3 -m venv cynthion-venv
    source cynthion-venv/bin/activate
    pip3 install --upgrade cynthion

Now let's test if everything works as expected:

    cynthion info --force-offline

Perhaps we need to update to the latest firmware:

    cynthion update
    cynthion info

As Cynthion can do different things, we need to configure it as analyzer by loading the right bitstream to the FPGA:

    cynthion run analyzer

To use the USB Analyzer as the default bitstream for the FPGA we can flash it to the FPGA:

    cynthion flash analyzer
    cynthion info

Now we can leave the virtual environment with deactivate. To reuse the cynthion hardware software we do again a source cynthion-venv/bin/activate.

Setting up Packetry, the analyzing software

The analyzing software is called Packetry and is written in Rust and uses GTK4. Packetry is fast and analysis the hardware USB bus packets. It can display them in a hierarchical way, that facilitates the interpretation of the traffic. You can save also the data as pcap-file and look at it with wireshark. But wireshark is less suitable to analyse USB data You can find explanations in the ShmooCon 2025 video.

The simplest way is to use an AppImage: https://github.com/greatscottgadgets/packetry/releases.

But its also interesting to learn how to run a Rust program on Linux. First we clone the repo:

    git clone https://github.com/greatscottgadgets/packetry.git
    cd packetry

Then we install rustc with the rustup tool and build Packetry with cargo:

    sudo apt install rustup build-essential libgtk-4-dev
    rustup default stable
    rustc -V
    cargo build --release

The Packetry binary is now in the folder target/release/.

I had two problems with Packetry.

After solving these problems, I was able to sniff the traffic.

Logging the traffic

Enumeration

We connect the PC with the software for our USB device (for me a Windows machine in Virtualbox) to the USB-C port labelled TARGET C. Now we start the record process in Packetry (red dot). After that we connect the USB device to the USB A port labelled TARGET A. After some seconds we can stop and save the enumeration process in a pcap-file.

Packetry
Click for a better view!

If we get nothing, the speed is wrong. Set the speed to low, full or high according to your device. If you don't know the speed, try one after the other.

The DP-100 used here works with full speed (12 Mbps).

Ok, we could use lsusb to get the device data, but in the device window it is easier to check than in a terminal. What do we have here?

The Manufacturer string is ALIENTEK, Product string ATK-MDP100, Vendor ID:0x2E3C, Product ID: 0xAF01

This helps already to write a udev rule for Linux, so that we don't need to be root to access the device.

    cd /etc/udev/rules.d
    sudo nano 55-ATK-MDP100.rules

Copy the following lines in the editor and save (Ctrl+o, Ctrl+x).

# DP100
SUBSYSTEM=="usb", ATTR{idVendor}=="2e3c", ATTR{idProduct}=="0af01", MODE="0660", GROUP="plugdev", TAG+="uaccess", TAG+="udev-acl", SYMLINK+="DP100%n"
KERNEL=="hidraw*", ATTRS{idVendor}=="2e3c", ATTRS{idProduct}=="0af01", MODE:="0660", GROUP="plugdev, TAG+="uaccess", TAG+="udev-acl""
    sudo udevadm control --reload
    sudo udevadm trigger

We get one configuration with one HID interface. The HID Interface has a descriptor with 32 bytes. Let's ask KI (chat mistral) to get the meanings and create a table. Here the result:

Byte Index Value (Hex) Description
0-1 06 FF Usage Page (Global Item) - Vendor-defined usage page (0xFF).
2 00 Reserved - Reserved byte, typically set to 0x00.
3-4 09 01 Usage (Local Item) - Vendor-defined usage (0x01).
5-6 A1 01 Collection (Main Item) - Begins an application collection.
7-8 15 00 Logical Minimum (Global Item) - Minimum value is 0x00.
9-10 25 FF Logical Maximum (Global Item) - Maximum value is 0xFF.
11-12 75 08 Report Size (Global Item) - Size is 8 bits.
13-14 95 40 Report Count (Global Item) - Count is 64 fields.
15-16 09 01 Usage (Local Item) - Vendor-defined usage (0x01).
17-18 81 02 Input (Main Item) - Defines an input report (Data, Variable, Absolute).
19-20 95 40 Report Count (Global Item) - Count is 64 fields.
21-22 09 01 Usage (Local Item) - Vendor-defined usage (0x01).
23-24 91 02 Output (Main Item) - Defines an output report (Data, Variable, Absolute).
25-26 95 01 Report Count (Global Item) - Count is 1 field.
27-28 09 01 Usage (Local Item) - Vendor-defined usage (0x01).
29-30 B1 02 Feature (Main Item) - Defines a feature report (Data, Variable, Absolute).
31 C0 End Collection (Main Item) - Ends the collection.

We have a vendor designed usage with an application collection. No HID class is used. HID is used to avoid a driver. The exchange is done with a field of 64 byte (8 bit). The meanings are only known to the vendor.

Data exchange

Next we use the windows software and connect to the device and disconnect again. By analyzing the IN and OUT transactions (we have only 2 endpoints), we see that the host PC sends always 0xFB as first byte (OUT) and the device 0xFA (IN). The second byte from the host seems to be a command. In the first OUT transactions we see 0x30, 0x10, 0x35 and 0x40. The byte is repeated by the device if it answers.

The third byte is always 0x00. The fourth byte (host) is 0x00 followed by 2 byte or 0x01 followed by 3 byte, so perhaps the length and a checksum. I asked again the KI and it took a bit longer to find that we have indeed the length of the following data followed by a checksum called CRC-16-Modbus.

Now it helps to use the Transaction Tab of Packetry to see the answer to a command. We see that the first answer of the device is:

    FA, 30, 00, 10,
    C8, 4E, 00, 00, 00, 00, 5E, 4C, 2F, 01, 2D, 01, CE, 13, 02, 00,
    92, 29,
    0E, 00, 0B, 00, AA, 00, 15, 89, 64, 12, 00, 00, 27, 70, 1D, 27,
    D9, 05, E8, 07, 08, 1D, 81, 49, 00, 00, 00, 00, 00, 00, 00, 00,
    00, 00, 00, 00, 00, 00, 00, 00, 00, 00

Ok strange. The length is 0x10, so 16 byte. I use an online calculator for the crc (crccalc.com) and yes, the result is 0x2992 for the first 19 byte. LSB first (little endian), but what of the following byte?

Let's assume that the data uses 2 byte (unsigned integer) and we use little endian. In decimal we get:

    20168, 0, 0, 19550, 303, 301, 5070, 2

Hey cool. By comparing with the win software we find the input voltage (20.16 V), perhaps the output voltage and current (0) and the system temperature (30.3 °C).

Ok let's connect a resistor and activate the Output.

    FA, 30, 00, 10,
    BD, 4E, 8D, 13, 17, 00, 5E, 4C, 43, 01, 48, 01, CD, 13, 01, 00,
    F9, 48,

The CRC is ok. Now we get

    19901, 5005, 23, 19550, 323, 328, 5069, 1

This shows now we definitively have the output voltage of 5 V and a current of 23 mA.

So the 0x30 command returns basic information. It seems we get two temperatures and also 2 additional voltages (19.55 V, 5,069 V (USB voltage?))

Next let's look at the answer of the 0x10 command:

    FA, 10, 00, 28,
    41, 54, 4B, 2D, 44, 50, 31, 30, 30, 00, FF, FF, FF, FF, FF, FF,
    0E, 00,
    0E, 00,
    0B, 00,
    AA, 00,
    15, 89, 64, 12, 00, 00, 27, 70, 1D, 27, D9, 05,
    E8, 07, 08, 1D,
    81, 49

Ther is some ASCII code! The first 9 byte give "ATP-DP100" :). So we have here device infos. Next we see two times 0x04 = 14. My hardware version is 1.4 and also the software version is 1.4. My serial number is 1D27D905

Interesting links