mcpField
U
usb-rea

usb-rea

本地服务
github.com/emirmrkaljevic开发工具2今天更新

关于 usb-rea

usb-rea 分析捕获的 USB 流量以推断设备协议,并生成带数据包证据链接的 Python/libusb 驱动。它面向研究仅能通过厂商软件控制的设备的开发者;项目处于 alpha 阶段,尚未在实体设备上测试。

主要功能

  1. 01捕获 USB 流量
  2. 02按标记的操作比较数据包
  3. 03推断字段、计数器和校验和
  4. 04分析设备响应和读数
  5. 05生成 pyusb 驱动及测试
  6. 06创建 Wireshark 解析器

适用场景

  1. 01研究仅有厂商软件的设备
  2. 02识别命令与响应数据包字段
  3. 03根据标记的捕获生成驱动
  4. 04通过 MCP 工具使用 USB 分析功能

MCP 相关

其 stdio MCP 服务提供流量捕获、标记、分析、报告、驱动框架生成、HID 解码、解析器生成及经确认后重放数据包等工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"emirmrkaljevic-usb-rea": {
"command": "uvx",
"args": [
"usb-rea"
]
}
}
}
启动命令uvx usb-rea

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypiusb-rea0.7.5

工具

9

收录的工具列表 · 更新于 今天

参数类型必填说明
businteger否用于 /dev/usbmonN 的 usbmon 总线编号 N;在 Windows/USBPcap 上忽略。默认值为 0
outstring否输出 pcapng 路径(如果已存在则覆盖)

详细介绍

usb-rea:逆向分析任意 USB 设备

ci license usb-rea MCP server

支持我的开源项目:购买 SkinToScan 套装
如果你觉得这个项目有用,可以购买我的另一个项目 SkinToScan 套装来支持我。这是一次性购买,收入将直接用于资助我的开源项目。

购买单张图片检查,€4.49 购买 5 张图片套装,€19.99(热门) 购买 15 张图片套装,€54.99

usb-rea 演示:捕获带标签的点击,获取协议和可用驱动程序

有一台 USB 设备只附带 Windows 厂商应用吗(机箱 LCD、RGB 控制器、鼠标、“智能”灯)?在厂商应用中点击操作时,usb-rea 会捕获 USB 流量(Linux 上使用 usbmon,Windows 上使用 USBPcap),按操作对数据包进行差异比较,推断协议,并编写开源 Python/libusb 驱动程序;每项结论都会关联到能够证明它的确切数据包。

状态:Alpha 阶段(v0.6.1,已发布在 PyPI)。已在合成设备、liquidctl 和 rivalcfg 文档记录的协议,以及公开的 Wireshark 捕获数据上验证(见 docs/VALIDATION.md)。尚未在实体设备上测试:欢迎提供你的捕获数据。

10 秒内试用(无需硬件)

pip install usb-rea
usb-rea demo --device fan
fan    100%  0x5a | counter (+1 per message) | 0x10 | u16be round(value * 1 + 0) | 0x00 | u16le crc16_modbus(bytes[0:6])
color  100%  0x5a | counter (+1 per message) | 0x20 | round(value * 1 + 0) | round(value[1] * 1 + 0) | round(value[2] * 1 + 0) | u16le crc16_modbus(bytes[0:6])
mode   100%  0x5a | counter (+1 per message) | 0x30 | lookup 1→0x11, 2→0x22, 3→0x47 | 0x00 | 0x00 | u16le crc16_modbus(bytes[0:6])

device replies:
fan    6/6  0xa5 | = query byte 2 (0x10) | = query byte 1 | u16le round(value * 1 + 0) | sum8(bytes[0:5])
poll 1 7/7  0xa5 | = query byte 2 (0x40) | u16le rpm = raw, seen 794..4012 | u8 temp = raw, seen 35..38 | mode: 0x00 = auto, 0x11 = silent, 0x22 = balanced, 0x47 = turbo | sum8(bytes[0:6])

21 of 21 'seen' observations matched a reply byte (mode, rpm, temp)

它会写入一份风扇控制器的合成捕获数据(其厂商应用还会轮询风扇状态,标记会注明应用屏幕上显示的内容:seen rpm 1207 temp 37 mode auto),还原协议和响应,为读数和风扇模式命名,并生成 report.md(每项结论都会关联到 Wireshark 帧编号)以及一个可用的 pyusb 驱动程序。该驱动程序能够编码从未见过的值,并解码风扇的响应。

--device lamp(默认值)是一个简单的 8 位设备;--device dial 会展示 32 位值和打包位域:

position     100%  0xa5 | 0x01 | u32le round(value * 1 + 0) | sum8(bytes[0:6])
level        100%  0xa5 | 0x02 | bits[0:4] = round(value * 1 + 0) | 0x00 | sum8(bytes[0:4])

可推断的内容

角色示例
固定报头 / 命令 ID5a、10 与 20、30
线性值,8、16 或 32 位,小端 / 大端,每个操作可包含多个值fan 2650 → 0a 5a;color 255 24 0;position 50000 → 50 c3 00 00
打包位字段(位与固定标志位相邻,包括跨两个字节的 12 位跨度)level 7 → b7 = 标志位 b0 + bits[0:4]
查找表(非线性选项)DPI 250→08,500→07……
循环计数器每条消息的序列字节 +1
校验和sum8、xor8、neg/inv sum8、sum16、CRC8、CRC8/MAXIM、CRC16 CCITT-FALSE/XMODEM/MODBUS/KERMIT
设备回复:回显的查询字节、映射到标签的值、读数状态轮询 → a5 40 2a 07 26 00 3c = RPM u16le 读数、温度 u8 读数、sum8
命名读数,依据供应商应用显示的内容(seen rpm 1180)字节 2-3 u16le rpm = raw,字节 4 temp = (raw - 40) / 2
开 / 关状态标志(seen pump on、seen pump off)字节 5 bit 0: pump (1 = on)
模式 / 枚举值(seen mode silent、seen mode turbo)字节 5 mode: 0x00 = silent, 0x02 = turbo,或与标志位相邻的 bits[4:6] profile: …
有符号读数,适用于应用显示负值的情况(seen temp -5)字节 4 i8 temp = raw,字节 2-3 i16be …

线性拟合必须通过留一交叉校验;否则 usb-rea 会退回到如实呈现的查找表,并说明这一点。

真实设备工作流(Linux)

sudo modprobe usbmon
usb-rea capture start -o lamp.pcapng
usb-rea mark -m lamp.pcapng.actions.json "brightness 0%"    # then click it in the vendor app
usb-rea mark -m lamp.pcapng.actions.json "brightness 50%"   # ...repeat for 3+ values per setting
usb-rea capture stop
usb-rea report lamp.pcapng -o report.md
usb-rea scaffold lamp.pcapng -o lamp_driver.py
usb-rea dissector lamp.pcapng -o lamp.lua      # Wireshark dissector for the same protocol

在 Windows 上使用 USBPcap/Wireshark 捕获,且没有标记?依次点击每个操作,并在两次点击之间稍作停顿,然后按顺序列出操作即可;usb-rea 会根据停顿拆分流量:

usb-rea report lamp.pcapng --labels "brightness 0%; brightness 50%; brightness 100%; power off; power on"
usb-rea scaffold lamp.pcapng --labels labels.txt -o lamp_driver.py   # one label per line

(如果有标记,它们是包含 {"label", "start", "end"} epoch 时间戳的 JSON 列表。)

大多数供应商应用也会自行轮询设备(每隔几百毫秒“获取状态”一次,并发送保活消息)。 usb-rea 会找出以稳定节奏发送的相同主机→设备消息,这些消息不会紧跟在你的点击之后,并会在拆分和比对前将它们单独列出;报告会在 忽略的后台流量 下列出这些消息及其周期和帧编号。始终紧跟在真实命令后面的固定“应用”数据包不会被视为后台流量。带序列号的轮询也能被识别:形状相同、仅有一个递增字节不同(以及随之变化的尾随校验和)的消息会显示为 aa 10 ?? 00 ?? 等形式。至少需要 8 个副本,因此不会把用户将数值每次递增 1 误判为轮询。

设备响应

设备也会回复:每条命令后发送 ACK,对每次轮询发送状态回复(RPM、温度、固件版本),或返回 GET_REPORT 的数据。usb-rea 会将每个查询与后续的 IN 传输配对(依据端点和典型延迟,因此在点击操作期间发送的轮询不会抢走该操作的回复),并使用相同机制解码回复:常量、回显查询内容的字节(命令 ID、序列号)、计数器、校验和,以及根据你的标签拟合的值(fan 1200 → 回复中的 u16le)。其他任何变化内容都会作为读数报告,并附上观测范围;报告会说明其含义未知。只有当一种字节序平滑变化、另一种则跳变时,才会判定为 16 位读数。生成的驱动会获得 query_<name>() 方法,用于发送查询、读取回复并返回一个字典({"reading_2": 1834, "checksum_ok": True, …})。 可使用 usb-rea demo --device fan 试用,也可对包含轮询的捕获数据试用。

为读数命名:告诉它厂商应用显示了什么

在说明读数是什么之前,它只是一串字节。采集时,记下厂商应用不时显示的内容:

usb-rea mark -m fan.pcapng.actions.json "seen rpm 1180 temp 34"   # several name/value pairs are fine

seen 标记是一条观察记录,而不是操作:它不会结束正在进行的操作,不会参与差异比较,也永远不会变成命令。每条观察记录都会与紧邻它之前(应用当时显示的内容)或之后、间隔不超过 1 s 的回复进行比较。如果某个名称对应的每条观察记录(至少 2 条,误差不超过一个单位或 1%)都相等,读数就会采用该名称;或者,如果线性公式 raw = value * scale + bias 能精确拟合这些记录,并通过与命令相同的逐条留出检查(至少 3 条且数值各不相同),读数也会采用该名称。系统还会尝试将相邻的两个字节读数作为一个 16 位 LE/BE 数值、将相邻的四个字节作为一个 32 位 LE/BE 数值(若高位字节仍为 0x00,三条观察记录就足够),因此能处理能量计数器和运行时间:mark "seen energy 2.968" 会将字节 1-4 命名为 u32be energy = raw / 1000。报告会显示公式及其依据的帧和标记时间,并列出没有匹配任何内容的观察记录;驱动会返回 {"rpm": 1180, "temp": 34, "ok": True, …}。

开/关状态也适用:mark "seen pump on, alarm off"(也支持 true/false、yes/no)。如果某个名称既出现过开启状态也出现过关闭状态,它就会成为状态标志:回复字节中的一位在应用显示开启时始终为 1,显示关闭时始终为 0;多个标志可以共用一个字节,驱动会返回 {"pump": True, "alarm": False, …}。如果两位始终同时翻转,它们将不被命名;报告会指出标志字节中发生变化但从未命名的位。

模式和其他枚举值用词语表示:mark "seen mode silent"、mark "seen profile gaming"(词语值放在最后,或逗号前:seen mode turbo, rpm 3900)。如果某个名称在至少 3 条观察记录中对应至少 2 个不同的词语,它就会成为模式:当应用显示某个词语时,回复字节的原始值每次都相同;而不同词语对应的原始值也不同。如果该字节的其他位会自行变化(或其中包含已命名的标志),系统只会采用词语之间存在差异的位,例如 bits[4:6] profile。报告会列出映射表(mode: 0x00 = silent, 0x02 = turbo)及其依据,JSON/MCP 字段会以 table 形式返回映射,驱动则会返回对应词语;对于从未见过的值,则返回原始数字:{"mode": "turbo", …}。如果应用显示负数(seen temp -5),系统也会尝试将最高位为 1 的 8 位和 16 位读数解释为有符号数(i8、i16le/i16be)。

如果某个较小的数字无法匹配整个字节(例如电池格数对应的 seen battery 3),系统也会在字节的部分位中查找:已命名标志或模式旁边的空闲位(截取为发生变化的位,因此固定的保留位会跳过)或任一半字节,例如 bits[1:4] battery;驱动会返回该数字。对于带小数显示的值(seen temp 41.5),系统也会尝试按十分位、百分位或千分位解释(原始值为 415,缩放比例为 10),因此只需两个这样的标记,无须像自由线性拟合那样提供三条。数字可以按应用显示的格式输入,支持小数逗号或千位分隔符:seen temp 41,5 °C, rpm 1,180 会被解析为 41.5 和 1180。

限制:只会命名回复(不会命名命令);如果一个名称符合两个位置,则不会采用该名称;模式只能占一个字节(或其中一组连续位),且只有你见过的词语才会获得标签;32 位读数永远不会按有符号数处理;不会尝试解析与其他位打包在一起的多位数值读数;如果显示舍入的粒度大于一个单位(例如 RPM 以 10 为步进显示),则只能使用恒等映射,不能使用缩放拟合。在 --labels 模式下,seen 标签没有时间戳,因此会被跳过。

MCP 服务

pip install usb-rea,然后将 usb-rea mcp 添加为 stdio 服务。工具:capture_start、capture_stop、mark_action、diff_actions、report、scaffold_driver、hid_descriptor(解码 HID 报告描述符/报告负载)、wireshark_dissector、replay_packet(未经人工确认时会拒绝执行)。对于不带标记的捕获,分析工具接受与 CLI 相同的 labels 参数。

使用 uv 时,无需安装:

{"mcpServers": {"usb-rea": {"command": "uvx", "args": ["--from", "usb-rea", "usb-rea", "mcp"]}}}

对于 Claude Code:claude mcp add usb-rea -- uvx --from usb-rea usb-rea mcp。该服务也列在官方 MCP Registry 中,名称为 io.github.emirmrkaljevic/usb-rea,并列在 Glama 上。Glama 会使用仓库的 Dockerfile 构建该服务,并检查它能否启动及列出其工具。

工作原理

  1. usb-rea capture start:记录流量(usbmon / USBPcap)
  2. usb-rea mark "brightness 50%":在厂商应用中为你执行的每个操作添加标签(mark "seen rpm 1180" 用于记录应用显示的内容)
  3. usb-rea diff:查看每个操作改变了哪些字节、数值关联、校验和及计数器
  4. usb-rea infer:生成消息模板和证据报告
  5. usb-rea scaffold:生成 pyusb 驱动和重放测试
  6. usb-rea dissector:为推断出的协议编写 Wireshark Lua 解码器
  7. usb-rea replay:向设备发送数据包(仅在明确确认后执行)
  8. usb-rea hid:从捕获数据(GET_DESCRIPTOR 0x22)或十六进制内容中解码 HID 报告描述符,并解码报告负载
  9. usb-rea mcp:将相同工具作为 MCP 服务提供给 AI Agent
Wireshark 解码器

usb-rea dissector capture.pcapng -o lamp.lua 会将推断出的协议转换为 Wireshark Lua 插件,让你可以继续捕获流量,并将其作为命令而非十六进制内容来读取:

wireshark -X lua_script:lamp.lua capture.pcapng
tshark -X lua_script:lamp.lua -r capture.pcapng -Y 'usbrea.command == "brightness"'

每个匹配的数据包都会生成一个 usbrea 树,其中包含命令名称、解码后的数值(usbrea.brightness.value)、计数器、查找标签和校验和检查(usbrea.checksum_ok,不匹配时会显示专家警告);Info 列会显示 brightness 50。它适用于 bulk、interrupt 和 control/HID SET_REPORT 传输,可处理来自 usbmon 或 USBPcap 的数据,且不需要 bit 库(Wireshark 3.x 和 4.x)。-n NAME 可更改过滤器前缀。CI 会使用 tshark 检查每个生成的解码器。

HID 设备

大多数 RGB 键盘、鼠标、耳机和 LCD 小设备都是带有厂商自定义页的 HID 设备。如果捕获数据中包含报告描述符(开始捕获后重新插拔设备),报告中就会包含一个区块,列出每份报告的 ID、大小和字段;每个推断出的命令也会标注其使用的 HID 报告。没有捕获数据时:

usb-rea hid /sys/class/hidraw/hidraw0/device/report_descriptor --items
usb-rea hid capture.pcapng --decode "10ff0d1d000000" --type Output

路线图

  • pcap/pcapng 解析器(usbmon + USBPcap)
  • 操作标记和逐操作差异比对
  • 校验和检测(sum8、xor8、neg/inv sum8、CRC8、CRC16 变体)
  • 有证据支持的协议报告
  • 驱动脚手架(pyusb、bulk/interrupt + control/HID SET_REPORT)
  • 已确认的重放
  • MCP 服务
  • 滚动计数器、多字节(16/32 位 LE/BE)值、查找表、多值操作
  • 打包位字段
  • 根据已记录的协议进行验证(liquidctl、rivalcfg)
  • HID 报告描述符解码(usb-rea hid),并将捕获的命令映射到对应的 HID 报告
  • 仿真设备 CI(dummy_hcd + configfs HID;脚本位于 scripts/gadget_e2e.sh)
  • 真实硬件案例研究
  • 多数据包事务(写入 + 应用),包括对较早数据包的校验和计算
  • 后台流量:检测并忽略定期状态轮询 / 保持连接信号
  • 设备响应:解码对命令、后台轮询和 GET_REPORT 的回复,提供 query_*() 驱动方法
  • 命名读数:seen rpm 1180 标记可命名并缩放回复读数(恒等或线性,8/16/32 位)
  • 开/关状态标志:seen pump on / seen pump off 可命名回复字节中的单个位
  • 模式 / 枚举值(seen mode turbo)和有符号读数(seen temp -5)
  • 与标志位打包的小型级别值(在状态字节的第 1–3 位中使用 seen battery 3)
  • 状态机(多步握手)

法律声明

为实现互操作性而进行的逆向工程受到允许(欧盟指令 2009/24/EC 第 6 条、美国 DMCA §1201(f))。usb-rea 仅分析你拥有的设备的流量,绝不再分发厂商代码。

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。