Binary Analysis 02 · 道具箱 — 何を使い、どう組み合わせるか

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 章)
道具の 7 分類眺めるxxd / hexdump / ImHex / 010 Editor拾うstrings / binwalk / file / grep -a測るbinwalk -E / ent / cmp / radiff2解く(形式)readelf / srec_cat / imgtool / Kaitai解く(コード)Ghidra / radare2 / objdump -d動かすOpenOCD / pyOCD / gdb / QEMU / Renode作るPython struct / construct / Kaitai取るOpenOCD / esptool / flashrom(4 章)基本の 4 つ = hexdump(xxd -e -g4)・strings・binwalk・Python の struct
眺める・拾う・測る・解く・動かす・作る・取る。まず基本の 4 つを手足のように

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 は無料・オープンソースで、本編の用途には十分である。

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             # 並べて目で見る

エントロピーの読み方は 03 章と 14 章で扱う。

5. 解く(形式)— 既知の形式の専用ツール

形式ツール章
ELFreadelf、objdump、nm、arm-none-eabi-* 版05
Intel HEX / SRECsrec_cat(srecord)、objcopy、Python の intelhex / bincopy06
MCUbootimgtool verify / dumpinfo08
UF2uf2conv.py08
LittleFSlittlefs-python(littlefs-fuse でマウントも可)09
FATmtools、7z、マウント09
NVM3Simplicity Commander commander nvm3 parse10
ESP-IDF NVSnvs_partition_gen.py(生成)、nvs_tool.py(解析。ESP-IDF 5.x)11
squashfs / JFFS2 / UBIFSunsquashfs、jefferson、ubireader15
汎用の構造定義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 -dELF があるならこれで十分なことも多い

使い方は 16 章で扱う。

7. 動かす — デバッガとエミュレータ

ツール役割
OpenOCDJTAG / SWD 経由で実機に接続。フラッシュ・RAM の読み書き、gdb サーバ
pyOCDPython 製。CMSIS-DAP / J-Link / ST-Link 対応。pyocd cmd で対話操作
J-Link CommanderSEGGER 製。savebin でダンプ、高速
gdb(arm-none-eabi-gdb / gdb-multiarch)ブレーク、メモリ表示、dump binary memory
QEMUCortex-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 / bu8 / i81
H / hu16 / i162
I / iu32 / i324
Q / qu64 / i648
f / dfloat / double4 / 8
4s4 バイトの生バイト列4
先頭の < / >リトル / ビッグエンディアン—

繰り返し構造を読むには struct.iter_unpack()、可変長や条件分岐のある構造には construct ライブラリ、可視化と多言語出力が欲しければ Kaitai Struct が向く(19 章)。

Python の struct — バイト列と整数を 1 行でimport structdata = open('work.bin','rb').read()sp, reset = struct.unpack_from('<II', data, 0) # 先頭 8 バイトを u32×2 にprint(hex(sp), hex(reset)) # 0x20000400 0x080081c5書式文字(先頭の < がリトル、> がビッグ)B/bH/hI/iQ/qf/d4su8/i8u16u32u64floatbytes繰り返し → struct.iter_unpack、可変長・条件 → construct、多言語・可視化 → Kaitai(19 章)
struct は固定構造に最適。

9. 作業環境の作り方

10. 手を動かす

作業から道具とコマンドを引く


この章のポイント