logicmso について
Saleae Logic MSOのキャプチャを分析するスキルで、ハードウェアのデバッグやプロトコル調査に使えます。バイナリエクスポートを読み込み、信号遷移やタイミングを調べ、一般的なプロトコルのデコード例を提供します。
主な機能
- 01Saleaeバイナリエクスポートの読み込み
- 02遷移時刻とパルス幅の分析
- 03タイミングヒストグラムとクラスタの生成
- 04UART、SPI、I2C、1-Wireのデコード
- 05未知のプロトコル分析例
活用シーン
- 01キャプチャ信号のタイミング確認
- 02未知の信号プロトコルの特定
- 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-apiPython パッケージ — むやみに 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 のヒント
- 未知のプロトコル:まず
analyze_protocol.py --clustersを実行して、タイミングの分布を確認します - 複数のチャネル:各チャネルを個別にエクスポートし、クロック線とデータ線を特定します
- 反転した信号:キャプチャによっては、論理レベルが反転しています
- タイミングの変動:実際のハードウェアにはジッターがあるため、しきい値ベースの検出を使用します
- 部分的なキャプチャ:キャプチャが送信の途中から始まっていないか確認します
- カスタムプロトコル:繰り返しパターンを探し、同期バイト/フレーミングバイトを特定します
トラブルシューティング
「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 に固定)になっている可能性があります
- 正しいチャネルがエクスポートされているか確認してください
- 元のキャプチャのトリガー設定を確認してください
タイミングが正しくないようです
- サンプルレートが元のキャプチャ設定と一致しているか確認してください
- 時間の単位(秒、ミリ秒、マイクロ秒)を確認してください