Binary Analysis 20 · ケーススタディ — 4 つの調査を最初から最後まで

Chapter 20

ケーススタディ — 4 つの調査を最初から最後まで

この章のゴール.

これまでの章の手順を、現実的な 4 つの調査の中で通しで使い、 「何をどの順で判断するか」を身につけること。 各ケースで、どの章の道具を、なぜ、その順で使うのかを追う。

各ケースは「状況 → 手順 → 判断」の形で示す。手を動かすデモ(ページ下部)で、簡略版を実際に操作できる。

この章で使う既出の用語(定義は各リンク先). エントロピー(01 章 3 節)、メモリマップ(01 章 3 節)、Ghidra(02 章 6 節)、binwalk(02 章 3 節)、CRC(03 章 8 節)、オフセット(03 章 1 節)、チェックサム(03 章 8 節)、SWD(04 章 2 節)、ブートローダ(04 章 5 節)、ELF(05 章 1 節)、ベクタテーブル(07 章 1 節)、ロードアドレス(07 章 10 節)、周辺レジスタ(07 章 7 節)、文字列(07 章 6 節)、MCUboot(08 章 1 節)、バージョン(08 章 3 節)、署名(08 章 4 節)、NVM3(10 章 1 節)、オブジェクト(10 章 4 節)、ページ(10 章 4 節)、バイナリ(12 章 3 節)、パターン(13 章 10 節)、秘密鍵(13 章 2 節)、圧縮(14 章 4 節)、Unicorn(17 章 9 節)

ケース A: 更新に失敗する機器

状況. STM32 + MCUboot の機器。OTA 更新後、旧バージョンに戻ってしまう。

手順.

  1. SWD でフラッシュ全体をダンプ(04 章)。2 回読んで一致を確認。SHA-256 を記録(01 章)
  2. binwalk とベクタテーブル(07 章)でメモリマップを作る。ブートローダ・slot0・slot1・設定領域に分ける
  3. slot0 と slot1 の MCUboot ヘッダ(08 章)を読む。バージョンは slot1 のほうが新しい(更新は届いている)
  4. 各スロットの末尾トレーラ(08 章)を読む。slot1 の image ok がセットされていない
  5. slot1 の TLV の SHA-256(08 章)を、アプリ本体から計算し直して照合 → 一致(イメージは壊れていない)

判断. イメージは正しく、署名も通っている。だが「テスト起動後にアプリが自身を確認(image ok を書く)する処理」が呼ばれていない。 アプリ側の「自己確認」ロジックが動いていないため、ブートローダが「確認されなかった」と判断してロールバックしている。アプリのコードを 16 章で確認する方向へ。

ケース A: 更新に失敗する機器ダンプSWD で全体、ハッシュ記録メモリマップBoot/slot0/slot1/設定MCUboot ヘッダslot1 が新しい = 更新は届いたトレーラslot1 の image ok が未セットSHA-256 照合一致 = 壊れていない判断イメージも署名も正しい。だがアプリの「自己確認(image ok を書く)」処理が呼ばれず、ブートローダがロールバックしている。アプリのコードを 16 章で確認へ
ヘッダ・トレーラ・image ok・SHA-256 でロールバックの原因を特定

ケース B: 設定が化ける

状況. EFR32(Zigbee)の機器。ときどき送信出力の設定が異常値になる。

手順.

  1. Simplicity Commander で NVM3 をダンプ(10 章)。commander nvm3 parse を試す → 一部のキーで「壊れている」警告
  2. 手動で NVM3 のページをたどる(10 章)。消去カウンタでページの新旧を並べる
  3. 問題のキーの全履歴を拾う。追記型なので過去の値が残っている
  4. 履歴を時系列に並べると、正常値の後に途中で切れたオブジェクトがあり、その後に異常値
  5. 切れたオブジェクトの位置は、あるページの末尾付近

判断. 設定書き込みの最中に電源が切れ、オブジェクトが不完全なまま残った。次回の読み出しで、その不完全なオブジェクトを(実装が)誤って有効と解釈し、異常値になった。 対策は書き込みの電源断耐性(18 章の破損の考え方)。プログラム側の NVM3 の使い方を見直す。

ケース C: 秘密が漏れていないかの監査

状況. 新製品の出荷前セキュリティレビュー。

手順.

  1. 量産設定のフラッシュをダンプ。まず読み出し保護が有効かを確認(04 章)→ 有効だったが、レビューのため保護を外した開発機でダンプ
  2. binwalk -E でエントロピーマップ(13 章・14 章)。高エントロピー区間を列挙
  3. 高エントロピー区間を圧縮/暗号/鍵に分類(14 章)。ファーム本体は暗号化なし(H≈6、コード)
  4. PEM / DER の証明書と鍵を検索(13 章)→ サーバの公開鍵と証明書はあるが、秘密鍵はない(正しい)
  5. 設定ストレージ(NVS)の全履歴を検査(11 章・13 章)→ 開発中に登録したテスト用 Wi-Fi パスワードが、削除済みマーカ付きで平文で残存
  6. パターンスキャン(13 章)で API キー・トークンを検索 → なし

判断. 致命的な鍵漏れはないが、(1) ファーム本体が暗号化されておらず読み出し保護だけが防御、(2) 削除したはずの資格情報が履歴に残る、の 2 点が指摘事項。 対策は PSA 編・IoT セキュリティ編(フラッシュ暗号化、セキュアエレメント、ストレージの適切な消去)。監査は 19 章でスクリプト化し、以後のビルドで自動化。

ケース C: 秘密が漏れていないかの監査① 読み出し保護の確認有効か。レビューのため開発機でダンプ② エントロピーマップ高エントロピー区間を列挙。ファーム本体は暗号化なし(H≈6)③ PEM/DER 検索公開鍵・証明書はあるが秘密鍵はない(正しい)④ NVS の全履歴検査削除済みマーカ付きのテスト用 Wi-Fi パスワードが平文で残存⑤ パターンスキャンAPI キー・トークンはなし判断: 致命的な鍵漏れはないが、(1) 本体が暗号化されず保護のみが防御、(2) 削除情報が履歴に残る、が指摘。対策は PSA / IoT セキュリティ編。監査は 19 章で自動化
保護確認・エントロピー・鍵/証明書検索・ストレージ履歴・パターンで自己監査

ケース D: 素性の分からないファーム

状況. 保守対象の古い機器。ソースもビルド環境も失われた .bin だけがある。

手順.

  1. file / strings / binwalk(02 章)。ELF ではない生バイナリ。文字列に "FreeRTOS V10.4.3"、"USART"、"/dev/..." はなし(ベアメタル/RTOS)
  2. 先頭を xxd -e -g4(07 章)。オフセット 0 が 0x20005000(RAM)、オフセット 4 が 0x08004401(フラッシュ・奇数)→ Cortex-M イメージ確定。ロードアドレスは 0x08004000 付近(ブートローダの後ろ)
  3. ベクタテーブルの繰り返しアドレスからデフォルトハンドラを特定、割り込み数からチップ系列を推定(07 章)
  4. Ghidra に ARM Cortex / ロードアドレス 0x08004000 / ベクタテーブルで読み込む(16 章)
  5. 文字列 "FreeRTOS V10.4.3" を XREF でたどり、スケジューラ初期化とタスク生成を特定(16 章)。周辺レジスタ 0x40013800(USART1)を触る関数から通信処理を発見
  6. 独自の設定チェックサム関数が見つかる。Unicorn でその関数だけ動かし(17 章)、既知の設定に対する出力を確認 → CRC-16/CCITT と判明

判断. ソースなしでも、使用 RTOS・通信周辺・設定形式が復元でき、保守に必要な範囲は把握できた。分かった構造は 19 章でパーサに残す。

ケース D: 素性の分からないファーム① file/strings/binwalk生バイナリ。RTOS/ベアメタルの手がかり② xxd -e -g4 で先頭0 が RAM、4 がフラッシュ奇数 = Cortex-M 確定。ロードアドレス推定③ ベクタテーブル繰り返しアドレス・割り込み数からチップ推定④ GhidraARM Cortex/ロードアドレス/ベクタで読み込み⑤ 文字列・周辺から機能"FreeRTOS" を XREF、0x40013800=USART1 で通信処理⑥ Unicorn で関数実行設定チェックサム関数 = CRC-16/CCITT と判明判断: ソースなしでも使用 RTOS・通信周辺・設定形式が復元でき、保守に必要な範囲を把握。構造は 19 章でパーサに残す
ベクタテーブル → ロードアドレス → Ghidra → 文字列/周辺 → Unicorn で素性を復元

まとめ — 共通する型

4 ケースに共通する流れ(01 章のワークフローの実践):

  1. 固定(ダンプの由来とハッシュ)
  2. 全体を見る(エントロピー・文字列・マジック)
  3. 地図(メモリマップ)
  4. 対象ごとに解く(各章の手順。公式ツール → 手動)
  5. 判断して記録(分かったこと・対策・パーサ)

そして繰り返し現れた原則:

デモ

4 つのケースを通しで追う


この章のポイント

これで全 20 章は終わりである。シリーズの目次に戻る。