mcpField
L
logicmso

logicmso

github.com/brownfinesecurityセキュリティ87541 回インストール21 週間前に更新
リポジトリ

logicmso について

Saleae Logic MSOのキャプチャを分析するスキルで、ハードウェアのデバッグやプロトコル調査に使えます。バイナリエクスポートを読み込み、信号遷移やタイミングを調べ、一般的なプロトコルのデコード例を提供します。

主な機能

  1. 01Saleaeバイナリエクスポートの読み込み
  2. 02遷移時刻とパルス幅の分析
  3. 03タイミングヒストグラムとクラスタの生成
  4. 04UART、SPI、I2C、1-Wireのデコード
  5. 05未知のプロトコル分析例

活用シーン

  1. 01キャプチャ信号のタイミング確認
  2. 02未知の信号プロトコルの特定
  3. 03UART、SPI、I2C通信のデコード

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/brownfinesecurity/iothackbot --skill logicmso

インストール後、Claude Code で/logicmsoを入力して読み込まれたか確認します。

同梱ファイルanalyze_protocol.pyexamples.md

詳細

Saleae Logic MSO 解析

このスキルでは、saleae-mso-api Python ライブラリを使用して、Saleae Logic MSO デバイスでキャプチャした信号を解析できます。バイナリエクスポートの読み込み、信号遷移の解析、一般的なプロトコルのデコードに対応しています。

前提条件

  • saleae-mso-api Python パッケージ — むやみに pip install しないでください。 まず、すでにインストールされているか確認します。
    python3 -c "from saleae.mso_api.binary_files import read_file; print('saleae-mso-api is available')"
    

確認に失敗した場合に限り、インストールします:pip install saleae-mso-api

  • Saleae Logic ソフトウェアからのバイナリエクスポートファイル(.bin 形式)

クイックリファレンス

バイナリファイルの読み込み
from saleae.mso_api.binary_files import read_file
from pathlib import Path

file_path = Path("capture.bin")
saleae_file = read_file(file_path)

# Access metadata
print(f"Version: {saleae_file.version}")
print(f"Type: {saleae_file.type}")

# Access data
contents = saleae_file.contents
デジタルキャプチャの構造

デジタルエクスポートには、次のチャンクを含む DigitalExport_V1 が格納されています。

chunk = saleae_file.contents.chunks[0]

# Key attributes:
chunk.initial_state      # Starting logic level (0 or 1)
chunk.transition_times   # numpy array of transition timestamps (seconds)
chunk.sample_rate        # Capture rate in Hz
chunk.begin_time         # Capture start time
chunk.end_time           # Capture end time
パルス幅の計算
import numpy as np

times = np.array(chunk.transition_times)
durations_ms = np.diff(times) * 1000  # Convert to milliseconds

# If initial_state is 0 (LOW):
#   - Even indices (0, 2, 4...) = HIGH pulse durations
#   - Odd indices (1, 3, 5...) = LOW gap durations
# If initial_state is 1 (HIGH):
#   - Even indices = LOW gap durations
#   - Odd indices = HIGH pulse durations

ヘルパースクリプト

このスキルには、一般的な解析タスク向けのヘルパースクリプトが含まれています。

プロトコルアナライザー
# Analyze signal characteristics
python3 skills/logicmso/analyze_protocol.py capture.bin

# Show detailed timing histogram
python3 skills/logicmso/analyze_protocol.py capture.bin --histogram

# Show detected timing clusters
python3 skills/logicmso/analyze_protocol.py capture.bin --clusters

# Export transitions to CSV
python3 skills/logicmso/analyze_protocol.py capture.bin --export transitions.csv

# Show raw transition values
python3 skills/logicmso/analyze_protocol.py capture.bin --raw -n 50

実際のキャプチャを最初から最後まで扱う例については、examples.md を参照してください。未知のプロトコルのトリアージと、実行可能な Python による UART、SPI、I2C、1-Wire のデコードを紹介しています。

一般的なプロトコルパターン

UART(非同期シリアル)
  • アイドル状態:HIGH
  • スタートビット:LOW(1 ビット期間)
  • データビット:8 ビット、LSB ファースト
  • ストップビット:HIGH(1~2 ビット期間)
  • 一般的なボーレート:9600、19200、38400、57600、115200
  • ビット期間の計算:1/baud_rate 秒
  • 識別の特徴:ビット期間が一定で、各期間が基本期間の倍数になっている
SPI(シリアル・ペリフェラル・インターフェース)
  • 4 つの信号:SCLK(クロック)、MOSI(マスター出力)、MISO(マスター入力)、CS(チップセレクト)
  • クロック極性(CPOL):アイドル時のクロック状態(0=LOW、1=HIGH)
  • クロック位相(CPHA):サンプリングエッジ(0=先行、1=後続)
  • データ:クロックエッジでサンプリングされ、通常はトランザクションあたり 8 ビット
  • 識別の特徴:規則的なクロック信号があり、トランザクション中は CS が LOW になる
I2C(Inter-Integrated Circuit)
  • 2 つの信号:SDA(データ)、SCL(クロック)
  • アイドル状態:どちらも HIGH(プルアップ)
  • スタート条件:SCL が HIGH のときに SDA が立ち下がる
  • ストップ条件:SCL が HIGH のときに SDA が立ち上がる
  • データ:8 ビット + ACK/NACK、MSB ファースト
  • アドレス:7 ビット(START の後の最初のバイト)
  • 識別の特徴:START/STOP 条件と、1 バイトあたり 9 クロックパルス(データ 8 ビット + ACK)
1-Wire
  • 単一信号:DQ(データ/電源)
  • アイドル状態:HIGH(プルアップ)
  • リセットパルス:マスターが最低 480us の間 LOW にする
  • プレゼンスパルス:スレーブが 60~240us の間 LOW にして応答する
  • Write 0:60~120us の間 LOW
  • Write 1:1~15us の間 LOW にしてから解放
  • 読み取り:マスターが LOW にした 15us 後にサンプリングする

解析ワークフロー

ステップ 1:初期調査
from saleae.mso_api.binary_files import read_file
import numpy as np

f = read_file("capture.bin")
chunk = f.contents.chunks[0]

print(f"Sample rate: {chunk.sample_rate/1e6:.1f} MHz")
print(f"Duration: {chunk.end_time - chunk.begin_time:.3f}s")
print(f"Initial state: {'HIGH' if chunk.initial_state else 'LOW'}")
print(f"Transitions: {len(chunk.transition_times)}")
ステップ 2:タイミングパターンの解析
times = np.array(chunk.transition_times)
durations_us = np.diff(times) * 1e6  # microseconds

# Separate HIGH and LOW durations
high_idx = 0 if chunk.initial_state == 0 else 1
high_durations = durations_us[high_idx::2]
low_durations = durations_us[(1-high_idx)::2]

print(f"HIGH pulses: min={min(high_durations):.1f}us, max={max(high_durations):.1f}us")
print(f"LOW gaps: min={min(low_durations):.1f}us, max={max(low_durations):.1f}us")

# Find unique timing values (cluster detection)
unique_high = sorted(set(round(d, -1) for d in high_durations))  # Round to 10us
unique_low = sorted(set(round(d, -1) for d in low_durations))
print(f"HIGH clusters: {unique_high}")
print(f"LOW clusters: {unique_low}")
ステップ 3:プロトコルの特定

タイミングパターンに基づいて特定します。

  • UART:ビット期間が一定で、各期間が基本期間の倍数になっており、アイドル状態は HIGH
  • SPI/I2C:us オーダーのタイミングで、クロック信号の解析が必要です。規則的なパターンを探します
  • 1-Wire:リセットパルスは約 480us、データパルスは 1~120us
ステップ 4:デコード

プロトコルを特定したら、そのプロトコルのルールに基づいてデコードします。未知またはカスタムのプロトコルの場合は、タイミングのクラスターとビットパターンを解析して、エンコーディング方式を特定します。

UART デコードの例

from saleae.mso_api.binary_files import read_file
import numpy as np

f = read_file("uart_capture.bin")
chunk = f.contents.chunks[0]
times = np.array(chunk.transition_times)

BAUD = 115200
BIT_PERIOD = 1 / BAUD

def decode_uart_byte(start_time, times, bit_period):
    """Decode a single UART byte starting at start_time."""
    byte_val = 0
    for bit_num in range(8):
        # Sample at center of each bit (1.5, 2.5, 3.5... bit periods from start)
        sample_time = start_time + (1.5 + bit_num) * bit_period
        # Find state at sample_time
        idx = np.searchsorted(times, sample_time)
        state = (chunk.initial_state + idx) % 2
        if state:
            byte_val |= (1 << bit_num)  # LSB first
    return byte_val

# Find start bits (falling edges when idle HIGH)
decoded_bytes = []
i = 0
while i < len(times) - 1:
    # Look for falling edge (start bit)
    if chunk.initial_state == 1 or i > 0:
        byte_val = decode_uart_byte(times[i], times, BIT_PERIOD)
        decoded_bytes.append(byte_val)
        # Skip to next potential start bit (after stop bit)
        i += 1
        while i < len(times) and times[i] < times[i-1] + 10 * BIT_PERIOD:
            i += 1
    else:
        i += 1

print("Decoded:", bytes(decoded_bytes))

CTF のヒント

  1. 未知のプロトコル:まず analyze_protocol.py --clusters を実行して、タイミングの分布を確認します
  2. 複数のチャネル:各チャネルを個別にエクスポートし、クロック線とデータ線を特定します
  3. 反転した信号:キャプチャによっては、論理レベルが反転しています
  4. タイミングの変動:実際のハードウェアにはジッターがあるため、しきい値ベースの検出を使用します
  5. 部分的なキャプチャ:キャプチャが送信の途中から始まっていないか確認します
  6. カスタムプロトコル:繰り返しパターンを探し、同期バイト/フレーミングバイトを特定します

トラブルシューティング

「No module named 'saleae.mso_api'」

まず、本当に見つからないことを確認します。

python3 -c "from saleae.mso_api.binary_files import read_file"

インポートに失敗した場合に限り、インストールします。

pip install saleae-mso-api
空または破損したファイル

ファイルサイズを確認し、Saleae Logic ソフトウェアから再エクスポートしてみてください。

遷移が検出されない
  • 信号が一定(HIGH または LOW に固定)になっている可能性があります
  • 正しいチャネルがエクスポートされているか確認してください
  • 元のキャプチャのトリガー設定を確認してください
タイミングが正しくないようです
  • サンプルレートが元のキャプチャ設定と一致しているか確認してください
  • 時間の単位(秒、ミリ秒、マイクロ秒)を確認してください

コメント