Binary

バイナリHACK

binwalkで解析できない場合などの、firmwareイメージを自力で解析する方法のメモです。Mac OS X El Capitanで実行しています。

stringsコマンド

バイナリに含まれる文字列を確認します。文字列のオフセットを確認することもできます。-8などを指定して長めの文字列を確認するとよいです。文字列が出てこない場合は圧縮などのエンコードされている可能性が高いです。

$ strings -t x original.bin | grep config.har
330000 config.har

オプションはmanページを確認してください。

hexdumpコマンド

バイナリを確認します。

$ hexdump original.bin
0000000 10 00 01 03 24 1a 00 00 10 00 02 9c 24 1a 00 01
0000010 10 00 02 d1 24 1a 00 02 10 00 02 cf 24 1a 00 03
0000020 10 00 02 cd 24 1a 00 04 10 00 02 cb 24 1a 00 05
0000030 10 00 02 c9 24 1a 00 06 10 00 02 c7 24 1a 00 07

grepしてgzipのヘッダーの"1f 8b 08"などを探します(binwalkでもやってくれますが)。またブロックの終端は0xffなどで埋まっていて、塊の見当がつけられます。

ddコマンド

バイナリの一部分を抜き出すことができます。

$ dd if=original.bin of=tp.gz bs=1 skip=262660 count=48702
48702+0 records in
48702+0 records out
48702 bytes transferred in 0.225961 secs (215533 bytes/sec)
$ file tp.gz
tp.gz: gzip compressed data, was "welkin-tp.b", from Unix, last modified: Fri Apr  9 01:01:29 2010, max compression

バラしたものを連結するときはcatコマンドで。

xxdコマンド

bootのコーンソールなどでアスキーダンプしたバイナリを元に戻せます。

$ head -1 hexdump.asc 
bfc40000:46 69 72 6d 77 61 72 65-00 ff ff ff ff ff ff ff Firmware........
$ sed 's/^.\{9\}//;s/.\{17\}$//' hexdump.asc | xxd -r -p > hexdump.bin

これらのコマンドとbootのコンソールを駆使して某ルータのflashイメージを解析したところこんな感じになってました。

WRFIRMWARE.png

ここまで解析するのはbinwalkだけでは無理なんで、職人の感と技でやるしかありません。

bootは64Kの2ブロックでhexdumpで見ると二つの部分に分かれているのがわかる。最初の部分は通常のインストラクションで、後半は圧縮された実行形式と思われるがgzipではなさそう。最初の部分を実行して後半をRAMに展開して実行を移していると思われる。

展開しているアドレスはカーネルのロードアドレスが0x80040000となっているので、それより前のアドレスになるようだ。

bootが管理するFirmwareなどのファイルの64K毎のセクタのヘッダー構造。tftpでpushするとできるので、直接操作することはないかもしれません。

タイプ バイト数 備考
ファイル名 16 NULLターミネートの文字列
ブロック番号 4
ファイルサイズ 4
? 4
? 36

Versionブロックはただの文字列。welkin-tp.bはテストプログラムで起動時やbootのコンソールでtpコマンドを実行すると読み込まれて処理を行うものと思われる。実際のfirmwareのnetbsdの部分だと想像される。

welkin-tp.bはgzip形式だがnetbsdは不明の形式。

Firmwareの中のブロックのヘッダー構造は調べた方がいてこんな感じのよう

タイプ バイト数 備考
フラグ 4 おそらく31ビットがgzipフラグ 17ビット目が実行可能フラグ 16ビットがENDフラグ
データ長 4
データ開始位置 4 0x18固定
チェックサム 2 データー長以降の16ビット単位のIPヘッダーと同様のチェックサム。と思ったのですがカーネルの部分だけ上位バイトが微妙にあいません。いくつかのファームウエアを調べていたところ、差がデータサイズに比例していることがわかりました。カーネル以外はサイズが小さいので、ちゃんと一致するというのもうなずけます。試しにデータ長を250000くらいで割った数字を足しこんでみたところうまくいくことがありました。
ダミー 2
ロードアドレス 4 実行可能な場合のロードアドレス
エントリーポイント 4 実行可能な場合のエントリーポイント

チェックサムの範囲は、短いデータのブロックで確認して見当をつけるのが良いです。

このターゲットのチェックサムは謎なので上記のロジックで適当にいじるとあたりがでます。

チェックサムがNGな場合

boot> load Firmware
Firmware system: load fail

チェックサムがOKな場合

boot> load Firmware
begin  : 0x80040100
length : 1807018
startup: 0x80040100

このターゲットにはrootfs部分が無いが、kernel内にufsとして入っているようだ。現在のCPUやメモリのスペックを考えると、あまり良い方法ではないきがする。

rubyなどで、構造をチェックするスクリプトを書くことも有効です。(例:EZ-USB FX2のfirmware抜き取りスクリプト)

objdumpでのアセンブラの解析も可能ですが、手間がかかるので本当に最後の手です。逆アセンブラの解析は現実的ではないのでAIを使った逆コンパイラがあると良いのですが。

$ objdump -b binary -m mips -D hoge.bin

解析にはQUEM上でバイナリを実行する方法もあるかもしれません。

バイナリを編集したいときはMacだとHex FiendというアプリがApp Storeにあって定番のようです。

スクリーンショット 2018-10-24 8.44.43.png