USB DMX, Part 2. The Handshake
Jul 29, 2019In 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
- URB ID, 8 Bytes
- URB Type, 1 Byte
- URB Transfer Type, 1 Byte
- Direction, 1 Byte
- Device ID, 1 Byte
- URB Bus ID, 2 Bytes
- Device Setup Request, 1 Byte
- Data Present, 1 Byte
- URB Second, 8 Bytes
- URB Micro-Second, 4 Bytes
- URB Status, 4 Bytes
- URB Length, 4 Bytes
- Data Length, 4 Bytes
- Step Header, 8 Bytes
- Interval, 4 Bytes
- Start Frame. 4 Bytes
- Copy of Transfer Flags, 4 Bytes
- Number of ISO Descriptors, 4 Bytes
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:
- String Length, 1 Byte
- Descriptor Type, 1 Byte
- String, 30 Bytes
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.
- Bytes 0-7 don’t change. This is controlled by the OS.
- Bytes 8-15 also don’t change, these are also controlled by the OS.
- Bytes 16-27 are time stamps, these will change but are controlled by the OS.
- Bytes 28-31 also don’t change, again controlled by the OS.
- Bytes 32-39 may change, but are descriptors and again controlled by the OS.
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.
More Posts