Honest Abe { HonestAbe }

USB DMX, Part 2. The Handshake

Jul 29, 2019

In the last part of this series we looked at capturing USB traffic using Wireshark and had a very brief look at what we can learn from the captured data. In this issue we’re going to look more at the analysis of the data, gain a better understanding of how USB data is structured and understand how we can begin the reverse engineering process behind USB devices. It’s not been said yet, but all of the techniques applied here can be used with any USB device, not just a DMX controller, but any piece hardware.

As promised in the last article here is my entire dump from Wireshark for my USB/DMX controller. This will help you follow along if you don’t have a device to test against, but more importantly it will show you that the captured data is generic enough to be shared with any developer on any machine. We’re analysing data, and our principals can be applied to any data set.

Breaking Down USB Data

The Header

The Handshake

For purposes of this article, the handshake is everything that needs to happen before the device and host can begin to communicate effectively. This happens with all devices, not just USB, and ensures that the host and device know how to communicate with each other.

There’s a few things we can do to determine which packets are the handshake packets, in our case we will be looking at sent time, packet size, and the data encapsulated in the packet.

No.     Time            Source  Destination Protocol Length Info
1       0.000000        host    3.3.0       USB      64     GET DESCRIPTOR Request DEVICE 
2       0.000400        3.3.0   host        USB      82     GET DESCRIPTOR Response DEVICE
3       0.000461        host    3.2.0       USB      64     GET DESCRIPTOR Request DEVICE
4       0.000653        3.2.0   host        USB      82     GET DESCRIPTOR Response DEVICE
5       0.000702        host    3.1.0       USB      64     GET DESCRIPTOR Request DEVICE
6       0.000714        3.1.0   host        USB      82     GET DESCRIPTOR Response DEVICE

The first, and most useful, indicator for us to look at is the Info column in Wireshark; This describes what the host or device is doing (it’s important to note the direction too). At first this may seem a little confusing or nonsensical and not all of the terms are especially descriptive of what they’re doing but a quick search will yield a wealth of knowledge.

You can see in our first 6 packets the host is polling a list of USB devices. If you’re running a laptop it may be picking up your touchpad, webcam, keyboard or other devices. Just aqquaint yourself with the devices connected to your machine and be sure that data is being captured on the correct device. We can ignore these first 6 packets as they’re not especially important for us, but always good to know about.

No.     Time            Source  Destination Protocol Length Info
7       4.374006        host    3.3.0       USB      64     GET DESCRIPTOR Request STRING
8       4.374130        3.3.0   host        USB      68     GET DESCRIPTOR Response STRING
9       4.374190        host    3.3.0       USB      64     GET DESCRIPTOR Request STRING
10      4.376330        3.3.0   host        USB      96     GET DESCRIPTOR Response STRING
11      4.376392        host    3.3.0       USB      64     GET DESCRIPTOR Request STRING
12      4.376495        3.3.0   host        USB      68     GET DESCRIPTOR Response STRING
13      4.376556        host    3.3.0       USB      64     GET DESCRIPTOR Request STRING
14      4.377830        3.3.0   host        USB      82     GET DESCRIPTOR Response STRING

The next 8 packets are where our data starts to get interesting. If we take a look at the string descriptor for Packet 10 we can see 32 bytes which contain:

If we read the string from here we can see it contains “FT232R USB UART”, the name of our device. Similarly if we look at packet 14 we can see the same structure but with the text “A100LF7C”, or the serial for our device. The easiest way to spot these packets in the future is by looking for “GET DESCRIPTOR” in the info column and the length of the packet data from the device to host. Look for anything above the average.

All of this data we can’t replicate, it’s the communications made between the device and the operating system and may change from system to system.

URB Control Packets

The next set of data we’re interested in is the URB Control packets, which handle sending data to and from the device. This is where we can tell the device how to behave and send DMX data down the line.

First up we need to find the packets which tell our device how to behave. As before we’re looking for the first large packet, as it’s likely this will be the one sending all the data.

No.     Time            Source  Destination Protocol Length Info
15      4.377975        host    3.3.0       USB      64     URB_CONTROL out
16      4.378047        3.3.0   host        USB      64     URB_CONTROL out
17      4.378121        host    3.3.0       USB      64     URB_CONTROL out
18      4.378195        3.3.0   host        USB      64     URB_CONTROL out
19      4.378264        host    3.3.0       USB      64     URB_CONTROL out
20      4.378339        3.3.0   host        USB      64     URB_CONTROL out
21      4.378403        host    3.3.0       USB      64     URB_CONTROL out
22      4.378478        3.3.0   host        USB      64     URB_CONTROL out
23      4.378544        host    3.3.0       USB      64     URB_CONTROL out
24      4.378592        3.3.0   host        USB      64     URB_CONTROL out
25      4.378612        host    3.3.0       USB      64     URB_CONTROL out
26      4.378664        3.3.0   host        USB      64     URB_CONTROL out
27      4.378697        host    3.3.0       USB      64     URB_CONTROL out
28      4.378739        3.3.0   host        USB      64     URB_CONTROL out
29      4.378780        host    3.3.0       USB      64     URB_CONTROL out
30      4.378813        3.3.0   host        USB      64     URB_CONTROL out
31      4.378828        host    3.3.0       USB      64     URB_CONTROL out
32      4.378859        3.3.0   host        USB      64     URB_CONTROL out
33      4.380097        host    3.3.0       USB      64     URB_CONTROL out
34      4.380136        3.3.0   host        USB      64     URB_CONTROL out
35      4.380324        host    3.3.0       USB      64     URB_CONTROL out
36      4.380358        3.3.0   host        USB      64     URB_CONTROL out
37      4.380452        host    3.3.2       USB      577    URB_BULK out
38      4.400164        3.3.2   host        USB      64     URB_BULK out
39      4.413173        host    3.3.0       USB      64     URB_CONTROL out
40      4.413239        3.3.0   host        USB      64     URB_CONTROL out
41      4.413424        host    3.3.0       USB      64     URB_CONTROL out
42      4.413476        3.3.0   host        USB      64     URB_CONTROL out
43      4.413558        host    3.3.2       USB      577    URB_BULK out
44      4.433254        3.3.2   host        USB      64     URB_BULK out
45      4.447068        host    3.3.0       USB      64     URB_CONTROL out
46      4.447119        3.3.0   host        USB      64     URB_CONTROL out
47      4.447293        host    3.3.0       USB      64     URB_CONTROL out
48      4.447341        3.3.0   host        USB      64     URB_CONTROL out

If we were to follow this data much further you’d begin to notice a pattern around the “URB_BULK” packets, specifically: 2 URB_BULK packets, followed by 4 URB_CONTROL packets (3 going to the device, and 3 coming back). From this, and the large packet size, we can assume this is where our DMX data starts to be sent, so we need to look at everything prior to that to understand how we can set our device up ready for recieving data.

With that in mind, and knowing that we only want to analyse packets going out from our host to our device let’s filter our packet list down…

No.     Time            Source  Destination Protocol Length Info
15      4.377975        host    3.3.0       USB      64     URB_CONTROL out
17      4.378121        host    3.3.0       USB      64     URB_CONTROL out
19      4.378264        host    3.3.0       USB      64     URB_CONTROL out
21      4.378403        host    3.3.0       USB      64     URB_CONTROL out
23      4.378544        host    3.3.0       USB      64     URB_CONTROL out
25      4.378612        host    3.3.0       USB      64     URB_CONTROL out
27      4.378697        host    3.3.0       USB      64     URB_CONTROL out
29      4.378780        host    3.3.0       USB      64     URB_CONTROL out
31      4.378828        host    3.3.0       USB      64     URB_CONTROL out
33      4.380097        host    3.3.0       USB      64     URB_CONTROL out
35      4.380324        host    3.3.0       USB      64     URB_CONTROL out

Much better, we can start to analyse this data now with a litte more ease. Let’s begin by looking at our URB Header for each packet and start noting some similarities.

Packet 15
80 d7 76 b3 02 88 ff ff 53 02 00 03 03 00 00 00
79 6a 22 5d 00 00 00 00 77 93 06 00 8d ff ff ff
00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Packet 17
80 d7 76 b3 02 88 ff ff 53 02 00 03 03 00 00 00
79 6a 22 5d 00 00 00 00 09 94 06 00 8d ff ff ff
00 00 00 00 00 00 00 00 40 03 38 41 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

etc.

If you were to analyse each of these packets you’d start to notice some similarities and we can ignore some of the bytes.

This leaves us with 24 bytes left to analyse, and it’s safe to say that if you check through the packets yourself there are only 4 that ever change: Bytes 40-43, the res of it is out handled by the operating system and not something we need to worry about. So, if we take a list of those remaing 4 bytes per packet we get a list of bytes that we need to send from host to device to ensure it is ready for our DMX data.

Our data we need to send in order:

40 00 00 00 
40 03 41 38
40 00 00 00 
40 04 10 08
40 02 00 00 
40 03 00 0c
40 00 00 01
40 00 00 02
40 01 02 00
40 04 50 08
40 00 00 02

Epilogue

Hopefully this has helped to clear things up a little with regards to USB handshakes and the thought process behind being able to reverse engineer them. As with any reverse engineering it takes a little understanding of the data structure and a lot of time to analyse the packets and learn what they’re doing and how we can replicate it.

It the next part we’ll be talking about the payload and how we can send DMX data to our fixtures before digging into any Golang goodies.

Read more from this series

More Posts