Chapter 02
道具箱 — 何を使い、どう組み合わせるか
この章のゴール.
「この作業にはこの道具」と迷わず選べるようになること。 全部を覚える必要はない。hexdump・strings・binwalk・Python の 4 つだけは手足のように使えるようにし、残りは名前と用途を知っておく。
この章で使う既出の用語(定義は各リンク先). エントロピー(01 章 3 節)
1. 道具の分類
| 分類 | 何をする | 代表 |
|---|---|---|
| 眺める | バイト列を 16 進と文字で表示する | xxd、hexdump、ImHex、010 Editor |
| 拾う | 文字列やマジックナンバーを見つける | strings、binwalk、grep -a、file |
| 測る | エントロピー、ヒストグラム、差分 | binwalk -E、ent、cmp、radiff2 |
| 解く(形式) | 既知の形式を構造として読む | readelf、objdump、srec_cat、imgtool、littlefs-python、Kaitai Struct |
| 解く(コード) | 機械語を逆アセンブル・逆コンパイルする | Ghidra、IDA、radare2 / Cutter、Binary Ninja |
| 動かす | 実機やエミュレータで実行し、メモリを見る | OpenOCD、pyOCD、J-Link、gdb、QEMU、Renode |
| 作る | 自分でパーサを書く | Python(struct、construct)、Kaitai Struct |
| 取る | フラッシュから中身を吸い出す | OpenOCD、pyOCD、flashrom、ベンダツール(04 章) |
2. 眺める — hexdump と GUI エディタ
16 進ダンプ(hexdump)は、バイト列を 1 バイト = 2 桁の 16 進数で並べ、右側に ASCII(英数字として読めるバイトだけ文字で表示。読めないものは .)を添える表示である。 すべての解析はここから始まる。
xxd -l 64 work.bin # 先頭 64 バイト
xxd -s 0x8000 -l 256 work.bin # オフセット 0x8000 から 256 バイト
xxd -e -g4 work.bin | head # 4 バイトごとにリトルエンディアンで表示(32 ビット値を読むとき)
hexdump -C work.bin | less # 同じ行が続くときは * で省略されるxxd -e -g4 は、Cortex-M のように 32 ビットリトルエンディアンの値が並ぶ領域(ベクタテーブル、ポインタ、長さ)を読むときに必須である。 バイト順のまま読むと 0x20000400 が 00 04 00 20 と見えて分かりにくい(03 章)。
GUI の 16 進エディタ(ImHex、010 Editor、HxD)は、次の点で CLI より優れる。
- パターン言語: 構造体を定義すると、バイト列に色を付けて構造として表示できる(ImHex のパターン、010 Editor のテンプレート)
- エントロピーやヒストグラムのグラフ
- 選択範囲を整数・浮動小数・文字列として即座に解釈する「データインスペクタ」
- ブックマーク(地図作りに便利)
ImHex は無料・オープンソースで、本編の用途には十分である。
3. 拾う — strings、file、binwalk
strings -n 8 work.bin # 8 文字以上の ASCII 文字列
strings -n 8 -t x work.bin # オフセット(16 進)付き
strings -e l work.bin # UTF-16 LE の文字列(Windows 系のデータ)
grep -a -o -b 'https\?://[[:print:]]*' work.bin # URL をオフセット付きで
file work.bin # 既知の形式なら種類を答える(ELF、gzip など)strings の出力で最初に探すのは、バージョン文字列・ライブラリ名・ファイルパス・printf のフォーマットである。 "FreeRTOS V10.4.3"、"mbed TLS 3.6.0"、"/home/dev/project/src/main.c"、"Error %d at line %d" は、使われている部品と構造を教えてくれる。
binwalk は、ファイルの中から既知のマジックナンバー(ファイル形式の先頭にある目印のバイト列)を全て探し、位置を一覧にする。
binwalk work.bin
# DECIMAL HEXADECIMAL DESCRIPTION
# 32768 0x8000 MCUboot image header, ... ← 形式によっては出ない
# 524288 0x80000 gzip compressed data, ...
binwalk -E work.bin # エントロピーのグラフを表示(要 matplotlib)
binwalk -e work.bin # 見つけた形式を展開(Linux イメージ向け。[15 章](15_Linux組み込みイメージ.md))binwalk のシグネチャは Linux 系のファイル形式が中心で、マイコン固有の形式(NVM3、NVS、ベクタテーブル)は検出しない。そこは本編の各章で自分でやる。 後継の unblob は展開の精度が高い。
4. 測る — エントロピーと差分
ent work.bin # 全体のエントロピー・カイ二乗など
binwalk -E work.bin # 区間ごとのエントロピー
cmp -l a.bin b.bin | wc -l # 違うバイトの数
cmp -l a.bin b.bin | head # 違う位置(1 始まりの 10 進オフセット、8 進の値)
radiff2 a.bin b.bin # radare2 の差分(16 進で見やすい)
vbindiff a.bin b.bin # 並べて目で見る5. 解く(形式)— 既知の形式の専用ツール
| 形式 | ツール | 章 |
|---|---|---|
| ELF | readelf、objdump、nm、arm-none-eabi-* 版 | 05 |
| Intel HEX / SREC | srec_cat(srecord)、objcopy、Python の intelhex / bincopy | 06 |
| MCUboot | imgtool verify / dumpinfo | 08 |
| UF2 | uf2conv.py | 08 |
| LittleFS | littlefs-python(littlefs-fuse でマウントも可) | 09 |
| FAT | mtools、7z、マウント | 09 |
| NVM3 | Simplicity Commander commander nvm3 parse | 10 |
| ESP-IDF NVS | nvs_partition_gen.py(生成)、nvs_tool.py(解析。ESP-IDF 5.x) | 11 |
| squashfs / JFFS2 / UBIFS | unsquashfs、jefferson、ubireader | 15 |
| 汎用の構造定義 | Kaitai Struct(.ksy で構造を書くと各言語のパーサと Web IDE の可視化が得られる) | 19 |
「公式ツールがあるならまず使う」(01 章)。自分で解くのは、ツールがない・壊れていてツールが読めない・ツールの出力の意味を確かめたい、ときである。
6. 解く(コード)— 逆アセンブラ
| ツール | 特徴 |
|---|---|
| Ghidra | 無料(NSA 製、オープンソース)。逆コンパイラ(機械語を C 風に戻す)を含む。Cortex-M 対応。本編の標準 |
| IDA Pro | 商用の定番。Free 版は x86 のみ |
| radare2 / Cutter | オープンソース。CLI が強力、Cutter は GUI |
| Binary Ninja | 商用。API が使いやすい |
arm-none-eabi-objdump -d | ELF があるならこれで十分なことも多い |
使い方は 16 章で扱う。
7. 動かす — デバッガとエミュレータ
| ツール | 役割 |
|---|---|
| OpenOCD | JTAG / SWD 経由で実機に接続。フラッシュ・RAM の読み書き、gdb サーバ |
| pyOCD | Python 製。CMSIS-DAP / J-Link / ST-Link 対応。pyocd cmd で対話操作 |
| J-Link Commander | SEGGER 製。savebin でダンプ、高速 |
gdb(arm-none-eabi-gdb / gdb-multiarch) | ブレーク、メモリ表示、dump binary memory |
| QEMU | Cortex-M の一部ボード(mps2、netduino)をエミュレート |
| Renode | 組み込み向けエミュレータ。多くのボードと周辺機器を再現 |
使い方は 04 章(ダンプ)と 17 章(動的解析)で扱う。
8. 作る — Python
本編で最も多用するのは Python である。理由は、struct モジュールでバイト列と整数の変換が 1 行で書けるからである。
import struct
data = open("work.bin", "rb").read()
sp, reset = struct.unpack_from("<II", data, 0) # 先頭 8 バイトをリトルエンディアンの u32 × 2 として
print(hex(sp), hex(reset))| 書式文字 | 型 | バイト数 |
|---|---|---|
B / b | u8 / i8 | 1 |
H / h | u16 / i16 | 2 |
I / i | u32 / i32 | 4 |
Q / q | u64 / i64 | 8 |
f / d | float / double | 4 / 8 |
4s | 4 バイトの生バイト列 | 4 |
先頭の < / > | リトル / ビッグエンディアン | — |
繰り返し構造を読むには struct.iter_unpack()、可変長や条件分岐のある構造には construct ライブラリ、可視化と多言語出力が欲しければ Kaitai Struct が向く(19 章)。
9. 作業環境の作り方
- Linux(または WSL)を勧める。上記ツールの大半が
aptで入る:sudo apt install binwalk srecord binutils-arm-none-eabi radare2 ent vbindiff - Python は仮想環境(
python -m venv)にintelhex bincopy construct kaitaistruct littlefs-python pyocdを入れる - Ghidra と ImHex は公式サイトからダウンロード
- ダンプを扱う作業ディレクトリは暗号化ボリュームに置く(鍵や個人情報が含まれるため)
10. 手を動かす
作業から道具とコマンドを引く
この章のポイント
- 道具は「眺める・拾う・測る・解く・動かす・作る・取る」の 7 分類
- hexdump(
xxd -e -g4)、strings、binwalk、Python の struct が基本の 4 つ - 既知の形式には専用ツール(readelf、srec_cat、imgtool、commander、Kaitai)
- 逆アセンブルは Ghidra、実機は OpenOCD / pyOCD、エミュレータは Renode / QEMU
- ダンプは秘密情報。作業場所は暗号化する