首页/新闻资讯/正文详情

USB流量分析实战:从HID协议到Wireshark/tshark还原键盘鼠标操作

发布时间:2026/9/25 6:25:43 来源:云帆数科 栏目:资讯中心
USB流量分析实战:从HID协议到Wireshark/tshark还原键盘鼠标操作
1. 从一份USB流量里找到键盘敲出的FlagCTF流量分析里USB流量算是杂项题中辨识度最高、套路最成熟的一类。题目通常给你一个.pcap或.pcapng文件描述是有人用键盘敲了一封信但捕获文件出了点问题或者干脆只留下一句HID Paster。懂的人扫一眼就知道这是USB键盘流量需要把键盘敲击事件还原成字符。如果不懂这题基本无从下手。USB流量分析的核心思路并不复杂USB设备在通信过程中主机会以URBUSB Request Block的形式记录每一次传输抓包工具把这些传输保存下来就形成了pcap文件。键盘、鼠标这类人机交互设备走的是USB HIDHuman Interface Device协议按键状态、坐标移动都编码在HID包的数据段里。我们需要做的就是从pcap中提取这些HID数据按照HID规范的编码规则解析最终得到键盘敲击的实际内容。这个过程需要几个前置知识一是能区分USB协议的不同传输类型二是能看懂HID报文的字节布局三是一张键盘按键编码映射表。别觉得这些内容枯燥把它们吃透了USB流量题就是送分题。本文按协议原理→工具准备→键盘流量实操→鼠标流量实操→常见坑的顺序完整拆一遍最后一个部分全是实测教训建议重点看。2. 动手前先把这几件事搞清楚2.1 为什么USB流量题通常一把梭能出结果流量分析一把梭是CTF圈里用来形容这类题型的一句话意思是只要掌握了正确的工具和过滤器拿flag就像一把梭那么快。USB流量题尤其适用这个形容因为它比HTTP、FTP这类明文协议流量分析更加机械化——HID报文结构固定、编码标准公开、解析逻辑几乎不需要任何上下文推断。从题目设计者的角度看USB流量题的目的不是让你去分析复杂的网络行为而是测试你对底层硬件协议的理解和耐心。所以这类题目通常不会在流量里做太复杂的混淆顶多在USB键盘流量的数据段加一个方向键、功能键的干扰或者在鼠标流量里把坐标做了简单变换。理解了这一点解题思路就清晰了先把所有USB事件过滤出来再按键盘/鼠标分类最后逐字节解析。2.2 认识一下USB HID协议里的包结构一个USB键盘产生的事件在pcap里通常是8字节数据结构是这样的第1字节修饰键Modifier Key记录Ctrl、Shift、Alt、Win这些功能键的状态bit 0到7分别对应左Ctrl、左Shift、左Alt、左Win、右Ctrl、右Shift、右Alt、右Win。第2字节保留字段恒为0x00。第3至第8字节普通按键的键值最多同时记录6个非修饰键。鼠标事件则通常是4字节数据第1字节鼠标按键状态bit 0为左键、bit 1为右键、bit 2为中键按下时为1。第2字节X轴位移有符号整数正数右移负数左移。第3字节Y轴位移有符号整数正数下移负数上移。第4字节滚轮部分捕获中不存在。这里有个特别容易踩的误区很多人以为第3字节的值就是ASCII码实际不是。它是HID键盘按键的Usage ID比如0x04代表字母a0x05代表b0x1E代表数字1。0x00表示该字节此时没有按键。所以要还原字符需要把Usage ID映射回ASCII这一步用Python脚本和网上的HID映射表都能解决。2.3 实操前需要准备的工具做USB流量分析不需要装复杂的系统环境一个熟悉Wireshark的人加一台能跑Python的电脑就够了。Wireshark用于初步观察流量结构确认USB传输类型和端点地址顺带做简单的过滤导出。tsharkWireshark的命令行版本批量提取HID数据日志时比图形界面稳定得多强烈建议直接使用。Python3写解析脚本。老手用Scapy也可以但纯文本解析在USB流量场景下反而更干净、更快没必要引入额外依赖。如果你用的是Windows记得把Wireshark安装目录加入系统PATH否则tshark会提示找不到命令。如果是Kali或Ubuntu这类Linux发行版直接用apt安装即可。3. 键盘流量分析完整实操3.1 第一步用tshark把所有键盘事件捞出来键盘设备在底层传输时数据走的是控制传输或中断传输。在USB捕获中一个键盘敲击事件通常以URB_INTERRUPT in的形式出现并且端点地址固定为0x81表示主机的端点1输入方向。既然我们已经有经验了一条tshark命令就能直接过一遍所有键盘数据tshark -r usb.pcap -Y usb.transfer_type 0x01 usb.endpoint_address 0x81 -T fields -e usb.capdata keyboard_data.txt这条命令的含义是读取usb.pcap过滤出传输类型为中断传输0x01且目标端点地址为0x81的包然后只输出HID数据字段usb.capdata到文件。如果数据包里没有capdata字段说明Wireshark没有正确解析URB结构这时可以改用-e usb.data看看。打完这条命令你要确认的是输出格式。正常情况下每一行是一串形如00:00:04:00:00:00:00:00的十六进制字符串每个冒号分隔一个字节。如果出现空行那多半是URB_COMPLETE事件里带有数据但过滤条件把某些键盘事件放过了这种情况后面细说。3.2 第二步写脚本解析按键并保留Shift按键拿到raw数据后下面的工作就是逐行解析。我直接给出一个可复用的Python脚本把修饰键和普通按键都解析出来并将HID Usage ID直接映射成ASCII字符#!/usr/bin/env python3 # -*- coding: utf-8 -*- hid_keyboard { 0x04: a, 0x05: b, 0x06: c, 0x07: d, 0x08: e, 0x09: f, 0x0a: g, 0x0b: h, 0x0c: i, 0x0d: j, 0x0e: k, 0x0f: l, 0x10: m, 0x11: n, 0x12: o, 0x13: p, 0x14: q, 0x15: r, 0x16: s, 0x17: t, 0x18: u, 0x19: v, 0x1a: w, 0x1b: x, 0x1c: y, 0x1d: z, 0x1e: 1, 0x1f: 2, 0x20: 3, 0x21: 4, 0x22: 5, 0x23: 6, 0x24: 7, 0x25: 8, 0x26: 9, 0x27: 0, 0x28: \n, 0x29: [ESC], 0x2a: [BACKSPACE], 0x2b: [TAB], 0x2c: , 0x2d: -, 0x2e: , 0x2f: [, 0x30: ], 0x31: \\, 0x33: ;, 0x34: , 0x35: , 0x36: ,, 0x37: ., 0x38: /, 0x39: [CAPSLOCK], 0x3a: [F1], 0x3b: [F2], 0x3c: [F3], 0x3d: [F4], 0x3e: [F5], 0x3f: [F6], 0x40: [F7], 0x41: [F8], 0x42: [F9], 0x43: [F10], 0x44: [F11], 0x45: [F12], 0x4f: [RIGHT], 0x50: [LEFT], 0x51: [DOWN], 0x52: [UP], } shift_keys { 1: !, 2: , 3: #, 4: $, 5: %, 6: ^, 7: , 8: *, 9: (, 0: ), -: _, : , [: {, ]: }, \\: |, ;: :, : , : ~, ,: , .: , /: ?, } def parse_hex_line(line): parts line.strip().split(:) if len(parts) 8: return None, None modifier int(parts[0], 16) key_value int(parts[2], 16) return modifier, key_value def convert(modifier, key_value): if key_value 0: return shift_pressed modifier 0x02 or modifier 0x20 if key_value in [0x28, 0x29, 0x2a, 0x2b, 0x39, 0x3a, 0x3b]: return hid_keyboard[key_value] base_char hid_keyboard.get(key_value, ) if base_char : return [UNKNOWN:0x{:02x}].format(key_value) if shift_pressed: return shift_keys.get(base_char, base_char.upper()) return base_char with open(keyboard_data.txt, r, encodingutf-8) as f: for line in f: mod, key parse_hex_line(line) if mod is None: continue ch convert(mod, key) if ch : continue print(ch, end)这个脚本按行读取之前tshark导出的keyboard_data.txt解析修饰键和按键值按Shift状态完成大小写和符号映射最后直接串成flag字符串。要注意的是系统对Shift的处理并不一定是常见的左Shift0x02也可能是右Shift0x20还有可能是Caps Lock状态。上面脚本里已经同时考虑了左Shift和右Shift但CapsLock的切换状态是一个全局状态不会记录在单条HID报文中所以如果题目明确使用了CapsLock需要额外维护一个状态标志读取到[CAPSLOCK]键值时翻转它。虽然这种题不常见但遇上了别慌加一个布尔变量就行。3.3 第三步踩过的坑——USB键盘流量为什么全是0x00我第一次实战时碰到一个特别迷惑的现象tshark导出的数据全是00:00:00:00:00:00:00:00跑完脚本一个字符也打印不出来。排查了半天才意识到过滤条件usb.endpoint_address 0x81筛出来的包是URB_COMPLETE事件但有的抓包环境尤其是Windows下用USBPcap抓的会额外产生URB_SUBMIT事件而真正的按键数据在URB_SUBMIT里。解法很简单过滤条件加上usb.urb_type URB_SUBMIT或者其他能区分事件类型的字段。更直接的方案是把usb.endpoint_address 0x81改成不指定端点地址只保留中断传输和方向字段tshark -r usb.pcap -Y usb.transfer_type 0x01 usb.endpoint_address 0x81 usb.urb_type URB_SUBMIT -T fields -e usb.capdata keyboard_data.txt如果你的tshark版本较老没有usb.urb_type这个字段名可以在Wireshark图形界面先点开一个键盘事件包看左侧树里有哪些字段名再照着改过滤条件。这里有个窍门Wireshark里右键某个字段选择作为过滤器应用或复制→复制为过滤器能直接拿到准确字段名比自己猜省事多了。3.4 键盘解析结果异常怎么办脚本跑完如果输出中出现大量[UNKNOWN:0x??]说明映射表里缺键值。常见的是方向键、Home、End这些编辑键也可能是多媒体键。这种情况下直接打开十六进制数据看一眼确认是哪个Usage ID然后补到映射表里即可。我遇到过一次题目把Shift的修饰键值设置为0x08也就是左Alt导致按a输出的是0x14q附近这种看似乱码的结果。解析这类题目时如果字符上下文明显不合理得想想是不是出题人故意改动了修饰键的位置。4. 鼠标流量分析完整实操4.1 鼠标轨迹如何还原成Flag鼠标流量题在CTF中出现的频率不如键盘高但一旦出现还原的通常不是字符而是轨迹坐标。这类题的典型场景是有人用鼠标画了一幅图或者用鼠标移动画出了flag需要把X、Y坐标提取出来连线绘图。鼠标HID数据比键盘简单4字节通常代表按键状态、X偏移、Y偏移、滚轮。我们只需要把X和Y偏移累加得到坐标序列再可视化即可。下面是提取脚本的核心逻辑#!/usr/bin/env python3 # -*- coding: utf-8 -*- with open(mouse_data.txt, r, encodingutf-8) as f: lines f.readlines() points [] x, y 0, 0 for line in lines: parts line.strip().split(:) if len(parts) 4: continue # 无符号字节转有符号 dx int(parts[1], 16) dy int(parts[2], 16) if dx 128: dx - 256 if dy 128: dy - 256 x dx y dy points.append((x, y)) with open(mouse_track.txt, w, encodingutf-8) as f: for p in points: f.write(f{p[0]} {p[1]}\n)输出mouse_track.txt后用matplotlib画散点图或线图import matplotlib.pyplot as plt with open(mouse_track.txt, r, encodingutf-8) as f: lines f.readlines() xs, ys [], [] for line in lines: x, y line.strip().split() xs.append(int(x)) ys.append(int(y)) plt.figure(figsize(10, 6)) plt.plot(xs, ys, linewidth1) plt.gca().invert_yaxis() plt.title(USB Mouse Trace) plt.show()这里有个细节Y轴方向。大多数屏幕坐标系是Y轴向下HID鼠标的Y正方向也是向下但有的绘图库默认Y轴向上画出来会是上下颠倒的轨迹所以我在代码里加了invert_yaxis()。如果画出来发现图形是镜像的去掉这一行再试试。4.2 鼠标左键和坐标之间的关系鼠标第1字节表示当前按下的键0x00表示没有按键0x01表示左键按下0x02表示右键按下。有些出题人把鼠标轨迹画成文字但只在按下左键时才实际落笔否则只是移动。此时需要把按键状态考虑进去只在左键按下时累加点左键释放时抬笔。button int(parts[0], 16) if button 0x01: x dx y dy points.append((x, y))如果不管按键状态全部累加最终图形会是所有移动路径的连接线可能完全看不出文字。这个坑我栽过一次题目其实是用鼠标在画板上写flag移动过程中从A点到B点的位移也产生了坐标连起来就是乱线。加了左键判断后立刻恢复了清晰的字形。5. 进阶场景与U盘流量混淆5.1 如何区分键盘流量和U盘流量有的题目会在一份pcap里同时包含USB键盘和U盘读写流量。U盘走的是Bulk Only TransportBOT协议和HID键盘这种中断传输不冲突所以用tshark过滤中断传输时不会混入U盘数据。问题的隐患在于另一类题目直接用USBPcap抓取时U盘数据的capdata字段也存在这时就不会混入U盘数据——实际上这里我想说的是如果抓包环境没有准确标记传输类型你先用Wireshark看Endpoint Address0x81中断输入基本就是键盘或鼠标0x02、0x03这类Bulk端点才是U盘。如果发现0x81上跑的是Bulk传输说明驱动枚举环境特殊按真实字段区分即可。如果想可视化查看端点分布在Wireshark里输入usb.endpoint_address选中一条后选择统计菜单里的端点能快速看到各个端点上的包数量。数量最多的那个端点大概率就是键盘或鼠标的主传输通道。5.2 多设备和无线键鼠的干扰问题现在是无线键鼠时代很多键鼠用的是2.4G接收器或蓝牙。这类设备在USB层面依然会被识别为HID设备但抓包时可能看到多份相似的流量端点甚至不止0x81。实操经验是先用usb.device_address过滤出当前活跃的设备再按端点地址细分。如果pcap里有多个键盘设备最简单的办法是只在特定usb.device_address上做键盘解析试一遍就能知道哪个设备对应题目里的敲击内容。还有一种情况是设备描述符解析受阻键盘数据被Wireshark标记成Malformed Packet。这通常需要手动跳过解析错误直接导出原始capdata。Wireshark里选择文件→导出分组解析结果→为Plain Text把包含capdata的行提取出来即可。5.3 出题人加盐右Shift、Caps Lock和异常键值做多了你会遇到出题人故意在键盘流里加入干扰键位。常见的有在正常按键之间穿插数字键盘的Usage ID比如0x54表示小键盘1因为部分题目环境用独立数字键盘输入这些键值需要单独建映射。Shift修饰键的位置被移动或复制到第5字节需要重新解析。正常字符串中混入退格字符0x2A。如果不处理你会拿到的flag多出字符或者空缺此时需要维护一个输出列表遇到[BACKSPACE]就弹出最后一个字符再继续。我自己写脚本时习惯在一开始就维护一个list而不是直接print这样处理退格、方向键这类可编辑键的时候最灵活。最终输出前用.join(chars)合并即可。6. 常见问题速查表与最终心得6.1 几个典型故障的排查记录现象可能原因排查方向tshark过滤完一行数据都没有端点地址或传输类型对应不上在Wireshark里手动点开USB包确认Urb Type字段名和Endpoint实际值导出数据全为00:00:...过滤到了URB_COMPLETE而非URB_SUBMIT加usb.urb_type URB_SUBMIT或直接换用usb.capdata ! 00:00...键盘解析出乱码Shift位判断错误或HID映射表缺项检查修饰键第1字节确认哪些bit被置位补全不常见键值鼠标轨迹上下颠倒或左右镜像Y轴方向或坐标累加符号问题调整invert_yaxis()或正负号用简单的矩形轨迹自测多个USB设备混在一起未按设备地址过滤用usb.device_address逐一过滤确定目标设备后单独提取退格键导致flag缺字符未处理0x2A解析脚本改用list暂存遇到退格pop最后一个元素pcap文件被标记为Malformed Packet抓包环境或设备描述符异常跳过显示直接按capdata字段手动解析十六进制6.2 我的一点实操心得USB流量题在CTF杂项里属于性价比极高的类型因为它的知识点集中、可复用性强。只要完整做过一套键盘和一套鼠标的解析流程之后遇到同类的题基本就是把tshark过滤条件和Python脚本复制过去跑一遍的事。正因如此我强烈建议你第一次做这类题时别急着搜现成脚本而是自己从Wireshark那一层开始把字段名、端点地址、HID字节布局一个一个搞清楚。这个过程花不了多少时间但是对这些细节的记忆会比别人直接给你脚本牢固得多。平时做题时可以把鼠标、键盘两套脚本整理成模板连同HID映射表一起存好。等到比赛现场再慌的脑子也能靠肌肉记忆快速出结果。最后再提醒一点拿到题目先看描述和附件名如果pcap文件名叫keyboard.pcapng或者题目写着HID Paster说明大概率是键盘题就别浪费时间去看HTTP请求了。先扫USB再考虑其他协议这是流量分析里最实用的先看设备后看网络原则。

相关推荐

零基础一小时C语言入门:从变量循环到数组指针的极简指南
零基础一小时C语言入门:从变量循环到数组指针的极简指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 6:25:31

CTF流量分析实战:USB键盘与鼠标流量提取与还原
CTF流量分析实战:USB键盘与鼠标流量提取与还原

CTF流量分析做了几年,USB这个方向真的是“老面孔”了。从入门赛到省级决赛,USB流量题几乎成了标配,尤其是键盘流量,几乎人手一把梭。但是很多人卡在不知道USB流量到底在说什么、键盘映射怎么处理、鼠标坐标怎么还原,更… · 2026/9/25 6:25:25

辉芒微MCU烧录校验全指南:从Hex到FMD-Link实操
辉芒微MCU烧录校验全指南:从Hex到FMD-Link实操

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 6:25:25

Packet Tracer 6.0 安装汉化全攻略:从下载到中文界面一步不踩坑
Packet Tracer 6.0 安装汉化全攻略:从下载到中文界面一步不踩坑

1. 为什么 2025 年还在写 Cisco Packet Tracer 6.0 的安装教程先说一个很现实的问题:Packet Tracer 现在都出到 8.x 了,官方下载页也早就把新版本放在最显眼的位置,为什么我还要专门写一篇 6.0 的安装和汉化教程?原因很简单——6.… · 2026/9/25 6:56:35

昇腾Atlas 300V 24G部署YOLO全流程:模型转换与推理实战指南
昇腾Atlas 300V 24G部署YOLO全流程:模型转换与推理实战指南

在AI推理这条路上摸爬滚打几年,手头最近分到一张华为昇腾Atlas 300V 24G运算加速卡,任务是在它上面把YOLO模型跑起来。说实话,一开始我也挺懵,网上关于Atlas部署YOLO的资料不是太零散就是讲得太理想化,真正能照着做的少… · 2026/9/25 6:56:29

Kubernetes Agent调度与Gateway实战:ax架构从零搭建指南
Kubernetes Agent调度与Gateway实战:ax架构从零搭建指南

1. 从"ax"这个标题说起:一个被低估的Agent调度入口第一次看到"ax"这个标题,很多人会以为是某个命令行工具的缩写,或者某个内部代号。但把热搜词摊开来看——ax调度、agent、kubernetes、workspace、gateway——这几个词凑… · 2026/9/25 6:56:29

超声波模块项目结构剖析:config.json、category.json、blocksdef.js、sonar.py四件套是如何协作的?
超声波模块项目结构剖析:config.json、category.json、blocksdef.js、sonar.py四件套是如何协作的?

超声波模块项目结构剖析:config.json、category.json、blocksdef.js、sonar.py四件套是如何协作的? 【免费下载链接】CupCode_HC-SR04超声波传感器模块 源师兄扩展项目: 超声波模块 | 由源师兄组织创建 项目地址: https://gitcode.com/yuanshixiong/ul… · 2026/9/25 6:56:17

mage-ai MySQL 数据源接入指南:配置参数、连接方式与源码实现解析
mage-ai MySQL 数据源接入指南:配置参数、连接方式与源码实现解析

数据工程数据编排ETL任务调度批处理流处理数据集成后端 【免费下载链接】mage-ai &#x1f9d9; Build, run, and manage data pipelines for integrating and transforming data. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ma/mage-ai 点击查看 免费下载 <输出… · 2026/9/25 6:56:11

技术写作:从代码到知识的工程化实践
技术写作:从代码到知识的工程化实践

1. 从代码到文字的蜕变之旅八年前那个加班的深夜&#xff0c;我在解决一个诡异的NullPointerException时&#xff0c;无意中把排查过程记录在了CSDN。没想到这篇随手写下的排错笔记&#xff0c;第二天就收到了几十条"感谢楼主&#xff0c;救了我一命"的评论。那一刻我… · 2026/9/25 6:56:11

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码