USB HID Reports are parsed with wrong bit order
Summary
USB HID Reports, where the 1-bit items are packed into a byte, are dissected assuming wrong bit order. The spec (Device Class Definition for HID 1.11) specifies LSb first (see e.g. the figure in 6.2.2), and actual hardware reports this way, while Wireshark interprets them assuming MSB-first order.
Steps to reproduce
- These steps assume Linux version of Wireshark
- In Wireshark, start
usbmonN
for your USB busN
where a keyboard is to be attached - Add a filter
usb.device_address==Y
whereY
is the address that will be assigned after you attach the device - Start capturing, make sure HID Report Descriptors have been captured
- Press LeftCtrl, LeftShift — these should set the first byte of the report to 0x03
- Find corresponding captured device→host packet
- See the following dissection:
HID Data: 0300110000000000
0... .... = Key: LeftControl (0xe0) = UP
.0.. .... = Key: LeftShift (0xe1) = UP
..0. .... = Key: LeftAlt (0xe2) = UP
...0 .... = Key: LeftGUI (0xe3) = UP
.... 0... = Key: RightControl (0xe4) = UP
.... .0.. = Key: RightShift (0xe5) = UP
.... ..1. = Key: RightAlt (0xe6) = DOWN
Padding: 80
Unknown: 00 (LED)
Keys: 110000000000
0001 0001 = Key: n (0x11)
Notice how above not only is one key missing (the LSB is ignored for some reason, although Usage Maximum is specified as 0xe7 in HID Report Descriptor), but also the wrong key shown as DOWN
.
What is the current bug behavior?
The first byte, corresponding to Report Size (1)
, Report Count (8)
, Usage Minimum (0xe0)
, Usage Maximum (0xe7)
, Input (Data,Var,Abs)
, is interpreted assuming wrong bit order.
What is the expected correct behavior?
Bits go from least significant to most significant, and 0x03 should be interpreted as LeftControl (0xe0)
and LeftShift (0xe1)
being DOWN
, while RightAlt (0xe6)
being UP
. Also, RightGUI
should be present and also shown as UP
.
Sample capture file
The following file was captured using the steps described above: wireshark-logitec-receiver-typed-in-two-interfaces-dev-addr-7.pcapng. Here the interesting HID Reports are in packets No. 151 (Ctrl down), 153 (Ctrl+Shift down), 165 (Ctrl+Shift+N down).
Build information
Wireshark 3.4.0 (Git commit 9733f173ea5e)
Copyright 1998-2020 Gerald Combs <gerald@wireshark.org> and contributors.
License GPLv2+: GNU GPL version 2 or later <https://www.gnu.org/licenses/gpl-2.0.html>
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Compiled (32-bit) with Qt 5.13.0, with libpcap, with POSIX capabilities (Linux),
without libnl, with GLib 2.56.1, with zlib 1.2.11, without SMI, with c-ares
1.14.0, without Lua, with GnuTLS 3.5.19 and PKCS #11 support, with Gcrypt 1.5.0,
with MIT Kerberos, without MaxMind DB resolver, without nghttp2, without brotli,
with LZ4, without Zstandard, without Snappy, with libxml2 2.9.4, with
QtMultimedia, without automatic updates, with SpeexDSP (using bundled
resampler).
Running on Linux 4.14.157-amd64-x32, with 3297 MB of physical memory, with
locale LC_CTYPE=ru_RU.UTF-8, LC_NUMERIC=en_US.UTF-8, LC_TIME=en_GB.UTF-8,
LC_COLLATE=en_US.UTF-8, LC_MONETARY=en_US.UTF-8, LC_MESSAGES=en_US.UTF-8,
LC_PAPER=en_US.UTF-8, LC_NAME=en_US.UTF-8, LC_ADDRESS=en_US.UTF-8,
LC_TELEPHONE=en_US.UTF-8, LC_MEASUREMENT=en_US.UTF-8,
LC_IDENTIFICATION=en_US.UTF-8, with libpcap version 1.7.2, with GnuTLS 3.5.19,
with Gcrypt 1.5.0, with zlib 1.2.11, binary plugins supported (0 loaded).
Built using gcc 7.5.0.