Why your mouse has a fingerprint
A USB device introduces itself before it is allowed to do anything. That introduction is a structured record, and it is far more specific than most people expect.
By Lethal Research
Plug in a mouse. Before a single cursor movement arrives, a short exchange has already finished. The host asked the device to describe itself. The device replied with a set of structured records. The host read those records to pick a driver and to learn what data to expect. This is the USB descriptor exchange, and it is mandatory. It is also why a device that only reports X and Y movement still has an identity of its own.
The device descriptor
Every USB device must be able to hand over exactly one device descriptor. It is a short record with a fixed layout. The host reads it with a control transfer before anything else, and cannot go on without it. Microsoft's driver documentation prints a real one, captured from a webcam with USBView. It is the clearest way to see the fields.
Device Descriptor:
bcdUSB: 0x0200
bDeviceClass: 0xEF
bDeviceSubClass: 0x02
bDeviceProtocol: 0x01
bMaxPacketSize0: 0x40 (64)
idVendor: 0x045E (Microsoft Corporation)
idProduct: 0x0728
bcdDevice: 0x0100
iManufacturer: 0x01
0x0409: "Microsoft"
iProduct: 0x02
0x0409: "Microsoft LifeCam VX-5000"
iSerialNumber: 0x00
bNumConfigurations: 0x01| Field | What it is | What the host does with it |
|---|---|---|
| bcdUSB | The USB specification revision the device claims to conform to. | Sets expectations about speeds and which features are available. |
| idVendor / idProduct | Vendor and product identifiers. Vendor IDs are allocated by USB-IF. | Windows constructs a hardware ID from them. This is the primary driver-matching key. |
| bcdDevice | A device-defined revision number. | Used together with idVendor and idProduct to generate hardware and compatible IDs. |
| iManufacturer / iProduct / iSerialNumber | Indexes into string descriptors the device also supplies. | Produces the human-readable names you see in Device Manager, and a serial if one is offered. |
| bDeviceClass and friends | Class, subclass and protocol codes. | Decide whether a generic class driver can claim the device at all. |
| bNumConfigurations | How many configurations the device offers. | The host then walks configuration, interface and endpoint descriptors underneath. |
The HID report descriptor is the interesting one
For a human interface device, the device descriptor is only the introduction. Under it sits a HID report descriptor, and that is a different kind of document. It is not a fixed record but a small program that states the shape of every report the device will send. It says, in effect: one byte of buttons, as five bits plus three spare bits. Then two 16-bit signed axes. Then an 8-bit wheel. The host builds a parser from that.
That freedom is why HID works for everything from a three-button mouse to a flight yoke. It is also why report descriptors stand apart. Two mice that feel the same in the hand can declare different report layouts. They can differ in usage pages, padding, resolution and feature reports. The descriptor is a design choice made by whoever wrote the firmware, and design choices carry a signature.
An input device that sits between a real mouse and a host must choose what to present upward. It can invent an identity. Or it can read the descriptors of the device plugged into it and pass those up. The second route is a different design, and it is why open passthrough firmware parses HID report descriptors at all. The MAKCM project documents doing exactly this. None of that is a detection claim in either direction. It only says which identity the host is given.
Looking at your own devices
- On Windows, USBView from the Windows Driver Kit prints the full descriptor tree for every attached device, HID report descriptors included.
- Device Manager shows the derived hardware IDs under Properties, Details, Hardware Ids. That string is literally built from idVendor, idProduct and bcdDevice.
- On Linux, lsusb -v prints device, configuration, interface, endpoint and HID descriptors for everything on the bus.
- A serial string is optional. Plenty of ordinary devices report iSerialNumber as zero. That means no string is offered.
# Linux: full descriptor dump for every attached USB device
lsusb -v
# Just the tree, with vendor:product IDs
lsusb -t
lsusbThe practical point is simple. A device that moves your cursor is not a nameless stream of deltas. It is a named participant on a bus, and it was named before it was allowed to move anything. Whether that matters to you depends on what is reading it. That is a separate question from whether the identity exists.
The guides behind this post
USB descriptors, VID/PID and what descriptor cloning means
12 min readA USB HID descriptor is how a device describes itself when plugged in: its vendor ID, product ID, strings and report format. Descriptor cloning means the input device presents the identity of the real mouse attached to it instead of its own generic one.
Open the guideArduino Leonardo and a USB Host Shield
11 min readAn Arduino Leonardo with a USB Host Shield is the cheapest working mouse passthrough: the shield's MAX3421E reads your mouse and the ATmega32u4 presents it. It is also the fiddliest: most shields expect Uno pin mapping and need SPI jumpered to the ICSP header.
Open the guideRead next
Questions about this? Ask on Discord
All posts