usb-rea について
usb-reaは取得したUSB通信を分析してデバイスのプロトコルを推定し、パケットの根拠を示すPython/libusbドライバーを生成します。ベンダーソフトで操作する機器を調べる開発者向けです。アルファ版で、実機では未検証です。
主な機能
- 01USB通信のキャプチャ
- 02ラベル付き操作ごとのパケット比較
- 03フィールド、カウンター、チェックサムの推定
- 04デバイス応答と読み取り値の分析
- 05pyusbドライバーとテストの生成
- 06Wiresharkディセクターの作成
活用シーン
- 01ベンダーソフト専用の機器を調査
- 02コマンドと応答パケットのフィールドを特定
- 03ラベル付きキャプチャからドライバーを生成
- 04MCPツール経由でUSB解析を利用
MCP 対応
stdio MCPサーバーは、キャプチャ、マーク、分析、レポート、ドライバーのひな型生成、HIDデコード、ディセクター生成、および確認後のパケット再生ツールを公開します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
9掲載時のツール一覧 · 今日に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| bus | integer | いいえ | /dev/usbmonN の usbmon バス番号 N。Windows/USBPcap では無視されます。デフォルトは 0 です |
| out | string | いいえ | 出力先の pcapng パス(既存の場合は上書き) |
詳細
usb-rea:あらゆる USB ガジェットをリバースエンジニアリング
このツールが役に立ったら、私のもう一つのプロジェクトである SkinToScan のパックを購入して支援できます。これは一度限りの購入で、私のオープンソースの活動に直接役立てられます。

Windows 専用のベンダーアプリしか付属しない USB デバイス(ケースの LCD、RGB コントローラー、マウス、「スマート」ランプなど)をお持ちですか?ベンダーアプリを操作すると、usb-rea が USB トラフィックをキャプチャし(Linux では usbmon、Windows では USBPcap)、操作ごとにパケットを比較して、プロトコルを推定し、オープンソースの Python/libusb ドライバーを書き出します。すべての結論には、それを裏付ける正確なパケットが紐付けられます。
状態:アルファ版(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])
推定できる内容
| 役割 | 例 |
|---|---|
| 固定ヘッダー/コマンド ID | 5a、10 と 20 と 30 |
| アクションごとに複数ある、8、16、32 ビットのリトルエンディアン/ビッグエンディアンの線形値 | fan 2650 → 0a 5a;color 255 24 0;position 50000 → 50 c3 00 00 |
| パックされたビットフィールド(定数フラグビットに隣接するビット。2 バイトにまたがる 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 … |
線形フィッティングは、1 件ずつ除外する相互検証に合格する必要があります。合格しない場合、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"} 形式のエポックタイムスタンプを並べた JSON リストです。)
ほとんどのベンダーアプリも独自にデバイスをポーリングします(数百 ms ごとの「ステータス取得」やキープアライブなど)。
usb-rea は、クリックとは関係なく一定のリズムで送信される、同一のホスト→デバイスメッセージを検出し、分割や差分比較の前に除外します。レポートでは、周期とフレーム番号を添えて Background traffic (ignored) に一覧表示します。実際のコマンドの後に常に続く一定の「apply」パケットは、バックグラウンドトラフィックとして扱いません。シーケンス番号を含むポーリングも検出します。1 バイトのカウントが 1 ずつ増えることと、それに伴って末尾のチェックサムが変わることだけが異なる、同じ形状のメッセージは、たとえば aa 10 ?? 00 ?? として表示されます。ポーリングと誤認してユーザーが値を 1 ずつ変更した操作を除外しないよう、少なくとも 8 個の複製が必要です。
デバイスの応答
デバイスも応答します。各コマンドの後の ACK、各ポーリングへのステータス応答(RPM、温度、ファームウェアバージョン)、または GET_REPORT のデータなどです。usb-rea は各クエリを、その後に続く IN 転送とペアにします(エンドポイントと通常の遅延を基準にするため、クリック中に送信されたポーリングがクリックへの応答を横取りすることはありません)。そして同じ仕組みで応答をデコードします。定数、クエリをエコーするバイト(コマンド ID、シーケンス番号)、カウンター、チェックサム、ラベルに当てはめた値(fan 1200 → 応答の u16le)などです。それ以外の変化する値は、観測された範囲とともに reading として報告され、意味は不明であることが示されます。16 ビットの測定値と判断するのは、一方のバイト順では値が滑らかに変化し、もう一方では値が飛び跳ねる場合に限られます。生成されるドライバーには、クエリを送信して応答を読み取り、dict({"reading_2": 1834, "checksum_ok": True, …})を返す query_<name>() メソッドが用意されます。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 秒以内の返信と照合されます。ある読み取り値が、その名前のすべての観測(2 件以上、誤差は1単位または1%以内)と一致する場合、または線形式 raw = value * scale + bias が観測に完全に一致し、コマンドと同じ1件抜き交差検証に合格する場合(値が異なる観測が3件以上)、その読み取り値に名前が付けられます。隣接する2バイトの読み取り値は1つの16ビットLE/BE数値として、4バイトは1つの32ビットLE/BE数値としても試されます(上位バイトがまだ 0x00 なら3バイトでも十分です)。そのため、エネルギーカウンターや稼働時間も扱えます。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ビットで、アプリがオンと表示したときは毎回1、オフと表示したときは毎回0になります。複数のフラグを1バイトで共有でき、ドライバーは {"pump": True, "alarm": False, …} を返します。常に同時に反転する2ビットには名前が付けられず、変化しているのに名前が付けられていないフラグバイトのビットはレポートに示されます。
モードなどの列挙値には単語を使います。mark "seen mode silent"、mark "seen profile gaming" のように記録します(単語の値は最後、またはコンマの前に置きます。例:seen mode turbo, rpm 3900)。3件以上の観測で、ある名前に異なる単語が2つ以上確認されると、その名前はモードになります。つまり、アプリにある単語が表示されるたびに同じraw値になり、単語が変わるとraw値も異なる返信バイトです。そのバイトのほかのビットが独立して変化する場合(または名前付きフラグを含む場合)は、単語間で異なるビットだけが使用されます。例:bits[4:6] profile。レポートには根拠とともに対応表(mode: 0x00 = silent, 0x02 = turbo)が表示され、JSON/MCP フィールドでは値が table として取得できます。ドライバーは単語を返し、未確認の値にはraw数値を返します。例:{"mode": "turbo", …}。アプリに負の数(seen temp -5)が表示される場合、最上位ビットがセットされる8ビットおよび16ビットの読み取り値も、符号付き(i8、i16le/i16be)として試されます。
1バイト全体に一致しない小さな数値(バッテリー残量バーの seen battery 3 など)も、バイトの一部から探されます。対象は、名前付きフラグやモードの隣にある未使用ビット(変化するビットだけに絞り、固定された予約ビットを除外)または片方のニブルです。例:bits[1:4] battery。ドライバーは数値を返します。小数で表示される値(seen temp 41.5)は、10分の1、100分の1、1000分の1としても試されます(raw 415、スケール10)。そのため、自由な線形フィットに必要な3件ではなく、こうしたマーカーが2件あれば十分です。数値は、アプリの表示どおりに、小数点としてのコンマや桁区切りを使って入力できます。seen temp 41,5 °C, rpm 1,180 は41.5と1180として読み取られます。
制限事項:名前を付けられるのは返信(コマンドではありません)だけです。2か所に一致する名前は除外されます。モードは1バイト(またはその中の連続したビット群)で、ラベルが付くのは観測した単語だけです。32ビットの読み取り値は符号付きとして扱われません。他のビットとともにパックされた複数ビットの数値読み取り値は試されません。また、表示上の丸めが1単位より粗い場合(例:RPMが10刻みで表示される場合)は、恒等変換でのみ機能し、スケーリングされたフィットでは機能しません。--labels モードの seen ラベルにはタイムスタンプがなく、スキップされます。
MCP サーバー
pip install usb-rea を実行し、stdio サーバーとして usb-rea mcp を追加します。ツール: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 からビルドし、起動してツール一覧を取得できることを確認します。
仕組み
usb-rea capture start:トラフィックを記録します(usbmon/USBPcap)usb-rea mark "brightness 50%":ベンダーアプリで行った各操作にラベルを付けます(mark "seen rpm 1180"は表示内容を記録します)usb-rea diff:操作ごとに変化するバイト、値の相関、チェックサム、カウンターを調べますusb-rea infer:メッセージテンプレートとエビデンスレポートを生成しますusb-rea scaffold:pyusb ドライバーとリプレイテストを生成しますusb-rea dissector:推定したプロトコルの Wireshark Lua ディセクターを作成しますusb-rea replay:パケットをデバイスに送信します(明示的な確認がある場合のみ)usb-rea hid:キャプチャ(GET_DESCRIPTOR 0x22)または16進数から HID レポートディスクリプターをデコードし、レポートペイロードをデコードしますusb-rea mcp:AI エージェント向けに、同じツールを MCP サーバーとして提供します
Wireshark ディセクター
usb-rea dissector capture.pcapng -o lamp.lua を実行すると、推定したプロトコルが Wireshark Lua プラグインに変換されるため、キャプチャを続けながら、トラフィックを16進数ではなくコマンドとして読み取れます:
wireshark -X lua_script:lamp.lua capture.pcapng
tshark -X lua_script:lamp.lua -r capture.pcapng -Y 'usbrea.command == "brightness"'
一致する各パケットには、コマンド名、デコードされた値(usbrea.brightness.value)、カウンター、ルックアップラベル、チェックサムの検証(usbrea.checksum_ok。不一致の場合はエキスパート警告)が含まれる usbrea ツリーが表示されます。Info 列には brightness 50 と表示されます。usbmon または USBPcap からのバルク、インタラプト、コントロール/HID SET_REPORT 転送に対応しており、ビットライブラリーは不要です(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-bit 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-bit) - オン/オフのステータスフラグ:
seen pump on/seen pump offで返信バイトの単一ビットに名前を設定 - モード/列挙値(
seen mode turbo)と符号付き読み取り値(seen temp -5) - フラグの隣にパックされた小さなレベル値(ステータスバイトのビット 1-3 にある
seen battery 3) - ステートマシン(複数ステップのハンドシェイク)
法的事項
相互運用性を目的としたリバースエンジニアリングは許可されています(EU 指令 2009/24/EC 第 6 条、米国 DMCA §1201(f))。usb-rea は所有するデバイスのトラフィックのみを解析し、ベンダーのコードを再配布することはありません。
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。