qedamameのブログ

Linuxコマンドでバイナリファイルを文字列置換

フォーマットに沿ったバイナリファイルを作った!
よし、これでテストができるぞ!
と思ったつかの間、フォーマットの認識を一部間違えていて、
まともにテストができない状態になってしまった。
すでにデータはすべて作り終え、テスト用の環境に配置し終えた後。
バイナリエディタで手作業で直していくのは現実的ではない。
労働先のPCなので勝手に便利ツールなどもインストールできないし、
どうしたものかと考える。

今回の自分のミスは、以下のような状態だった。

・バイナリファイルに誤って書き込んだ値がわかっている
・訂正後の値もわかっている
・その値は12バイトなので、ファイル内の関係ない箇所と値は重複しない

そのため、文字列置換を実施できれば御の字。

実施内容は以下の通り。
1.xxd でバイナリファイルを16進数でダンプし、テキストとして扱えるようにする。
2.sedで文字列置換を行う。
3.xxdで置換後のテキストを再びバイナリ化する。
4.バイナリデータをファイル出力。

xxd -p -g 0 -c 100000000000000 before.bin | sed s/${before}/${after}/g | xxd -p -r > after.bin


1.xxd でバイナリファイルを16進数でダンプし、テキストとして扱えるようにする。

xxd -p -g 0 -c 100000000000000 before.bin
  • p で、プレーン形式でダンプできる。

バイナリエディタの左隅に表示される、行頭のアドレスみたいなのを表示させない。

  • g で、バイトごとに空白をいれるか指定。0指定なので、空白無し。
  • c で、1行に表示させる桁数を指定。

デフォルトは16、最小1、最大256らしいが、-pを併せて設定することで256より大きな値を設定できるという裏技を見つけた。
これで、バイナリファイルの中身を16進数一行のテキストとして扱えるようになった。


2.sedで文字列置換を行う。

sed s/${before}/${after}/g

${before}の文字列を${after}へ置換。
わざわざ一行のテキストに整形したのは、空白や行端が混じって、${before}が見つけられなくなる可能性があるため。


3.xxdで置換後のテキストを再びバイナリ化する。
4.バイナリデータをファイル出力。

xxd -p -r > after.bin
  • r で、16進ダンプをバイナリに変換。

ダンプ時に-p をつけた際は、バイナリ変換時にも-pが必須。


実際には、以下のようなシェルスクリプトを作成し、テスト環境下のデータを一気に変換していった。
置換前と置換後の文字列の組み合わせ一覧をテキストファイルにまとめ、
テスト用の環境の中から変換対象のバイナリファイルををfindで探し、
xargsで最初のxxd(16進ダンプ用)に渡す。
テキストを読み込み、置換対象の文字列を順番に探す。


以上。