目次
はじめに
久しぶりにURoad-Homeの方に触れます。今回はフラッシュのダンプを取ってみます。
URoad-Home関係の記事とその概要の一覧はこちら
大まかな流れ
大まかな流れとしては、U-Boot上でmdコマンドを使ってフラッシュのバイナリをコンソールに出して、それをteratermのログ機能で保存します。その後、Pythonを用いてバイナリファイルに変換します。
U-Bootのカーネルパラメータ(bootarg)を変更してもうまく行かず、今回の方法と次の記事で書くOSコマンドインジェクションでダンプを取ることができました。今回は前者の方法を書きます。後者は次回の記事で書きます。
手順
1. U-Bootのコンソールに入る
URoad-Homeを分解してみた2を元にteratermで接続できU-Bootのコンソールに入っている状態にしてください。
2. ログを記録する
Teratermの機能であるログの保存を使用します。
右上のファイル→ログから適当な場所に適当な名前で保存してください。
1つのパーティションに1つのログファイルとすると良いです。追記・上書き保存に気をつけてください。
3. mdでのフラッシュのバイナリを出力
BF000000からフラッシュのアドレスとなるので、それぞれのパーティションを表示させるには
bootloader:md BF000000 40000
Config:md BF040000 20000
Factory:md BF060000 20000
Kernel:md BF080000 730000
Kernel2:md BF7C0000 730000
Wimax:md BFF00000 100000
となります。Wimaxに関しては無理やりC0000000を読もうとしてクラッシュするので注意が必要です。
1つのログファイルに1つのパーティションとしてください。一度にフラッシュのすべてを読み出すこともできますが、番地が飛んだりして面倒なことになるのでおすすめしません。
4. ログの取得を終了
5. 2~4を繰り返してすべてのパーティションのログファイルを取得する
6. ログファイルを整える
ログファイルの1行目は実行したコマンド、最終行には、uroad-3000>みたいなのが記録されているので、メモ帳などで開き、それを取り除きます。
7. ログファイルをバイナリファイルに変換
mdで表示をすると右側にアドレス、中央にバイナリ、右にアスキーコードがでるので、中央のバイナリ部分を抽出してバイナリファイルを作成します。
Pythonを使用します。以下のコードを使用しました。
import sys
import os
def log2bin(file_path):
# ログファイルからバイナリデータを抽出し、新しいバイナリファイルに書き込む
# 入力ファイル名から拡張子を分離
base_name, ext = os.path.splitext(file_path)
# 出力ファイル名の生成(入力ファイル名をbinに)
output_file_path = f"{base_name}.bin"
# ログファイルを読み込み、各行からバイナリデータを抽出して新しいバイナリファイルに書き込む
with open(file_path, 'r') as file, open(output_file_path, 'wb') as output_file:
for line in file:
# 各行からバイナリ部分のみを抽出
binary_data = line[10:49].replace(" ", "")
# バイナリデータをバイト配列に変換してファイルに書き込む
output_file.write(bytes.fromhex(binary_data))
return output_file_path
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python script.py <input_file>")
else:
input_file_path = sys.argv[1]
output_file_path = log2bin(input_file_path)
print(f"Converted file saved as: {output_file_path}")
ログファイル(例teratermlog.log)を引数として与えて、実行するとバイナリファイル(teratermlog.bin)に変換してくれます。ログファイルがあるのと同じディレクトリで実行してください。
8. リトルエンディアンをビッグエンディアンに変換
取得したファイルはすべてリトルエンディアンとなっており、そのままではbinwalkなどが全く使用できないので、変換します。先程と同じようにPyhtonを使用します。以下のコードを使用しました。
import sys
import os
def convert_endian(input_file_name):
# 入力ファイル名から拡張子を分離
base_name, ext = os.path.splitext(input_file_name)
# 出力ファイル名の生成(入力ファイル名に "_endian" を追加)
output_file_name = f"{base_name}_endian{ext}"
# ファイルを読み込み、各32ビット(4バイト)ごとにエンディアンを変換する
with open(input_file_name, 'rb') as input_file, open(output_file_name, 'wb') as output_file:
while True:
# 4バイトずつ読み込む
chunk = input_file.read(4)
if not chunk:
break
# エンディアンを変換に変換
converted_chunk = chunk[::-1]
output_file.write(converted_chunk)
return output_file_name
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python script.py <input_file>")
else:
input_file_path = sys.argv[1]
output_file_path = convert_endian(input_file_path)
print(f"Converted file saved as: {output_file_path}")
リトルエンディアンのファイルteratermlog_binary.binをビッグエンディアンに変換し、teratermlog_binary_endian.binとして出力します。使い方は、引数に変換したいファイル名を指定してください。
9. 確認
FavBinEditなどでバイナリファイルを開き、抜けが無いか確認します。行数が足りるかどうかで確認すると良いです。UARTなので信頼性が低いので必須です。
解析
とりあえずbinwalkにかけてみた感じです。
Bootloader
U-Bootです。
Config
U-Bootのconfigかな
Factory
Configのバックアップか、nvramですかね
Kernel
Linuxカーネル、LZMAが確認できます。展開は後でします。
Kernel2
Kernelのバックアップです。U-Bootのコンソールでbootm BF7C0000
とかすると起動できます。多分Kernelと同じ内容です。
Wimax
とてつもない量が出力されます。ファイルシステムがJFFS2のことはわかるんですが、展開しても似たようなものしか出てきません。
/の展開
今回はramdiskとなっているので、Kernelを
binwalk -Me Kerenelのバイナリファイル
で実行すれば展開でき、ファイルを確認できます。
telnetが入ってますね。/etc/passwdが見当たりません。nvramから読み出して使ってるのかな…
焼き直す
ミスした時とかに本体にダンプファイルを焼く時は、U-Boot上でtftpbootかloadbでメモリにコピーし、フラッシュをeraseしてcpして焼く感じになると思います。なお、ビッグエンディアンのバイナリファイルではなく、リトルエンディアンのファイルを焼くことに注意してください(再変換か、変換前のファイルか)。
おわりに
U-Bootのmdコマンドでダンプを取るという話を聞いたことがあったので試してみました。思ってたよりは時間もかからず楽でしたが、一度に全部のダンプを取ろうとすると抜けが発生してしまい、完璧では無いなーって感じでした。
実を言うと、Wimax以外のパーティションは次の記事で紹介するOSコマンドインジェクションを使ってダンプを取りました。そっちのほうが楽な気がします。
URoad-Home関係の記事とその概要の一覧はこちら