USB 协议
USB HID 键盘的输入报告(通常是 8 字节)格式如下:
1 | [modifier] [reserved] [key1] [key2] [key3] [key4] [key5] [key6] |
modifier:修饰键状态,按位表示reserved:保留字节,固定为0x00key1~key6:当前按下的最多 6 个普通键的键码(Usage ID)。若不足 6 键,剩余位置填0x00
Modifier 字节定义
modifier 字节中每个 bit 对应一个修饰键,可同时组合(按位或)
| 位 | 掩码 (Hex) | 修饰键 |
|---|---|---|
| Bit 0 | 0x01 |
Left Control (左 Ctrl) |
| Bit 1 | 0x02 |
Left Shift (左 Shift) |
| Bit 2 | 0x04 |
Left Alt (左 Alt) |
| Bit 3 | 0x08 |
Left GUI (左 Win / ⌘) |
| Bit 4 | 0x10 |
Right Control (右 Ctrl) |
| Bit 5 | 0x20 |
Right Shift (右 Shift) |
| Bit 6 | 0x40 |
Right Alt (右 Alt / AltGr) |
| Bit 7 | 0x80 |
Right GUI (右 Win / ⌘) |
常见键码 (Keycode / Usage ID)
键码来自 USB HID Usage Tables 的 Keyboard/Keypad Page (0x07)。下面列出最常用部分
字母键(A – Z)
| 按键 | 键码 (Hex) | 按键 | 键码 (Hex) |
|---|---|---|---|
| a / A | 0x04 |
n / N | 0x11 |
| b / B | 0x05 |
o / O | 0x12 |
| c / C | 0x06 |
p / P | 0x13 |
| d / D | 0x07 |
q / Q | 0x14 |
| e / E | 0x08 |
r / R | 0x15 |
| f / F | 0x09 |
s / S | 0x16 |
| g / G | 0x0A |
t / T | 0x17 |
| h / H | 0x0B |
u / U | 0x18 |
| i / I | 0x0C |
v / V | 0x19 |
| j / J | 0x0D |
w / W | 0x1A |
| k / K | 0x0E |
x / X | 0x1B |
| l / L | 0x0F |
y / Y | 0x1C |
| m / M | 0x10 |
z / Z | 0x1D |
主键盘数字与符号
| 按键 | 键码 (Hex) | 按键 | 键码 (Hex) |
|---|---|---|---|
| 1 / ! | 0x1E |
6 / ^ | 0x23 |
| 2 / @ | 0x1F |
7 / & | 0x24 |
| 3 / # | 0x20 |
8 / * | 0x25 |
| 4 / $ | 0x21 |
9 / ( | 0x26 |
| 5 / % | 0x22 |
0 / ) | 0x27 |
常用控制键
| 按键 | 键码 (Hex) | 按键 | 键码 (Hex) |
|---|---|---|---|
| Enter (回车) | 0x28 |
Caps Lock | 0x39 |
| Escape (ESC) | 0x29 |
F1 | 0x3A |
| Backspace | 0x2A |
F2 | 0x3B |
| Tab | 0x2B |
F3 | 0x3C |
| Space (空格) | 0x2C |
F4 | 0x3D |
| - / _ | 0x2D |
F5 | 0x3E |
| = / + | 0x2E |
F6 | 0x3F |
| [ / { | 0x2F |
F7 | 0x40 |
| ] / } | 0x30 |
F8 | 0x41 |
| \ / | | 0x31 |
F9 | 0x42 |
| ; / : | 0x33 |
F10 | 0x43 |
| ‘ / “ | 0x34 |
F11 | 0x44 |
| ` / ~ | 0x35 |
F12 | 0x45 |
| , / < | 0x36 |
Print Screen | 0x46 |
| . / > | 0x37 |
Scroll Lock | 0x47 |
| / / ? | 0x38 |
Pause | 0x48 |
导航与编辑键
| 按键 | 键码 (Hex) | 按键 | 键码 (Hex) |
|---|---|---|---|
| Insert | 0x49 |
Page Down | 0x4E |
| Home | 0x4A |
Right Arrow | 0x4F |
| Page Up | 0x4B |
Left Arrow | 0x50 |
| Delete | 0x4C |
Down Arrow | 0x51 |
| End | 0x4D |
Up Arrow | 0x52 |
数字小键盘 (Keypad)
| 按键 | 键码 (Hex) | 按键 | 键码 (Hex) |
|---|---|---|---|
| Num Lock | 0x53 |
4 (Left) | 0x5C |
| / | 0x54 |
5 | 0x5D |
| * | 0x55 |
6 (Right) | 0x5E |
| - | 0x56 |
7 (Home) | 0x5F |
| + | 0x57 |
8 (Up) | 0x60 |
| Enter | 0x58 |
9 (Page Up) | 0x61 |
| 1 (End) | 0x59 |
0 (Insert) | 0x62 |
| 2 (Down) | 0x5A |
. (Delete) | 0x63 |
| 3 (Page Down) | 0x5B |
实战案例
difficult programming language

打开流量包发现是 USB 流量

USB 键盘的数据包一般是 8 字节 HID report
modifier表示 Shift / Ctrl / Alt 等组合键key1~key6表示当前按下的键码
1 | [modifier][reserved][key1][key2][key3][key4][key5][key6] |

万能提取脚本
1 | pcap_path = "difficult_programming_language.pcap" |
运行后得到
1 | D'`;M?!\mZ4j8hgSvt2bN);^]+7jiE3Ve0A@Q=|;)sxwYXtsl2pongOe+LKa'e^]\a`_X|V[Tx;:VONSRQJn1MFKJCBfFE>&<`@9!=<5Y9y7654-,P0/o-,%I)ih&%$#z@xw|{ts9wvXWm3~c |
结合题目文件名 difficult_programming_language
很容易联想到著名的 “困难编程语言”
1 | Malbolge |
把整段输入作为 Malbolge 代码直接执行时,会发现最后一个字符 c 会导致源码校验失败
Malbolge 源码中,每个位置的字符需要满足特定规则
1 | (ord(ch) + index) % 94 ∈ {4, 5, 23, 39, 40, 62, 68, 81} |
去掉最后一个字符后,得到合法 Malbolge 程序
1 | D'`;M?!\mZ4j8hgSvt2bN);^]+7jiE3Ve0A@Q=|;)sxwYXtsl2pongOe+LKa'e^]\a`_X|V[Tx;:VONSRQJn1MFKJCBfFE>&<`@9!=<5Y9y7654-,P0/o-,%I)ih&%$#z@xw|{ts9wvXWm3~ |
可以用 Python 的 malbolge 库执行
1 | import malbolge |
拿到 flag:hctf{m4lb0lGe}