「\x00」バイトを含むバイナリストリームの編集

「\x00」バイトを含むバイナリストリームの編集

シェルツールのみを使用してNULL(0x00文字)を含むバイナリストリームを編集し、出力ストリームで0x00文字を保持するにはどうすればよいですか?

編集するには、以下のように指定された位置の1文字を別の文字(以下の例では「|」文字)に置き換える必要があります。

dd ibs=1 skip=$offset count=$reglen status=none if=$ARQ |
        sed 's/./\|/2' |
        sed 's/./\|/5' #| more replacements....

ただし、sedは置き換える前に '\ 0x00'文字をすべて削除します。

編集 - @George Vasiliouのテストを使用して、私の環境でsedの動作を表示します。

$ echo -e "lineA\nlineB\nlineC" | tr '\n' '\0' | od -t x1
0000000 6c 69 6e 65 41 00 6c 69 6e 65 42 00 6c 69 6e 65
0000020 43 00
0000022

$ echo -e "lineA\nlineB\nlineC" | tr '\n' '\0' | sed 's/./|/5' | od -t x1
0000000 6c 69 6e 65 7c 6c 69 6e 65 42 6c 69 6e 65 43
0000017

私の環境はAIX 7.1で、sedにはGNUバージョンはありません。

答え1

sedテキスト便利です。それは適用されますテキスト行(改行で区切られた非NUL文字(バイトではない)の制限された長さのシーケンス)。

2番目5番目を変更したい場合 バイトバイトシーケンスですが、いくつかの理由で動作しません。

  • sedテキストに適用されます。入力にNUL文字が含まれていて、改行で終わらず、2つの改行の間にLINE_MAXバイト以上があり、有効な文字を形成しないバイトシーケンスが含まれていると(実装に応じて)sedまったく機能しません。 (GNUにはsedこれらの制限はほとんどありません。)
  • 対応するバイナリ入力が有効なテキストを形成しても、バイト以外の文字.と一致するため、複数のバイトが一致する可能性があります。
  • sedコードはそれぞれに対して実行されるためワイヤー入力の2番目と5番目の文字は、入力全体の2番目と5番目の文字ではなく、各行の2番目と5番目の文字を変更します。

入力をNULバイト制限や長さ制限なしで任意のバイト配列として扱うには、次のようにしますperl

 dd.... | perl -0777 -pe 'for $o (1, 4) {substr($_, $o, 1) = "|"}'

例:

$ printf 'a\0b\0cd' |
>   perl -0777 -pe 'for $o (1, 4) {substr($_, $o, 1) = "|"}' |
>   od -Ax -tx1 -tc
000000  61  7c  62  00  7c  64
         a   |   b  \0   |   d
000006

vimあるいは、ヘルパーを使用して中間テキスト表現を使用することもできますxxd

dd... | xxd -p | sed '1s/../7c/2;1s/../7c/5' | xxd -p -r

xxd -pデフォルトでは、16進ダンプは1行に60文字で提供されます。上記の最初の行の2番目と5番目の2桁の16進数字を7cASCII数字に置き換えました|

答え2

努力するベイベイ、sedに似たバイナリストリームエディタです。

マニュアルページ

bbeはsedに似たバイナリファイルエディタです。 sedのように入力を1行ずつ読み取る代わりに、bbeは入力ストリームからランダムチャンクを読み取り、見つかったチャンクに対してバイト依存変換を実行します。

答え3

確かですか?簡単なテストでは、私の場合はこれが起こらないようです(gnu sed 4.2.2)。

$ echo -e "lineA\nlineB\nlineC"
lineA
lineB
lineC
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0'
lineAlineBlineC
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/5'
line|lineBlineC
# Verification if the nulls are still there:
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/5' |tr '\0' '\n'                                                                                                
line|
lineB
lineC

追加のテストの後、テストで6番目の文字(空の位置)を置き換えると、nullが失われます。

$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/6' |tr '\0' '\n'
lineA|lineB 
lineC

$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/7' |tr '\0' '\n'
lineA
|ineB           
lineC 

関連情報