ハッシュ関数をテストする必要があり、特定のファイルの1ビットのみを変更したい。
Ddコマンドで試してみました。これでうまくいきますが、変更できるのはバイトではなく、バイト全体です。
Sudo dd if=/dev/zero of=/file.bin bs=1 seek=10 count=1 conv=notrunc
また、正規表現を使用してsedコマンドを試しましたが、ファイルの内容がわからないため、「a」を「b」に変更することはできません。
誰かがこれを行うためのコマンドを知っていますか?
ファイルにはnullが含まれている可能性があるため、sed
のようなテキスト指向のフィルターは失敗します。ただし、Perl
やpython
などのnullを処理できるプログラミング言語を使用できます。 Python 3.の解決策です。読みやすくするために、厳密に必要な長さよりも数行長くなっています。
#!/usr/bin/env python3
"""Toggle the bit at the specified offset.
Syntax: <cmdname> filename bit-offset"""
import sys
fname = sys.argv[1]
# Convert bit offset to bytes + leftover bits
bitpos = int(sys.argv[2])
nbytes, nbits = divmod(bitpos, 8)
# Open in read+write, binary mode; read 1 byte
fp = open(fname, "r+b")
fp.seek(nbytes, 0)
c = fp.read(1)
# Toggle bit at byte position `nbits`
toggled = bytes( [ ord(c)^(1<<nbits) ] )
# print(toggled) # diagnostic output
# Back up one byte, write out the modified byte
fp.seek(-1, 1) # or absolute: fp.seek(nbytes, 0)
fp.write(toggled)
fp.close()
ファイル(bitflip
など)に保存し、実行可能にして、変更するファイル名とオフセットビット単位で実行します。ファイルがその場で変更されることに注意してください。同じオフセットで2回実行すると、ファイルが復元されます。
単一のコマンドがあるとは思わない。以下は簡単なスクリプトです。「flipbit
」という名前で保存してください:
#!/usr/bin/Perl
# Arguments: byte (starting from 0), bit (0-7), filename (otherwise stdin)
$byte = shift(@ARGV);
$bit = shift(@ARGV);
undef $/;
$file=<>;
substr($file,$byte,1) = substr($file,$byte,1) ^ chr(1<<$bit);
print $file;
テスト:
$ echo abb | ~/bin/flip-bit.pl 2 0 | od -xa
0000000 6261 0a63
a b c nl
これにより、3番目の文字の下位ビット(0)が反転し、「b」が「c」に変更されました。
単一行コマンドとして:
Perl -e '$byte=shift(@ARGV);$bit=shift(@ARGV);undef $/; $file=<>; substr($file,$byte,1) = substr($file,$byte,1) ^ chr(1<<$bit); print $file'
最後に、xxd
とdd
の解決策を見つけました。
a=$(xxd -b -l 1 -seek 3 -p a.bin);b=1;echo -e "\x$((${a}^${b}))" | dd of=a.bin bs=1 seek=3 count=1 conv=notrunc
hexdump a.bin v
0000000 61 39 73 36 36 64 66 38 61 39 73 64 35 36 66 35
0000010 37 61 73 64 37 66 74 75 61 67 73 0a 61 73 64 66
hexdump b.bin v
0000000 61 39 73 37 36 64 66 38 61 39 73 64 35 36 66 35
0000010 37 61 73 64 37 66 74 75 61 67 73 0a 61 73 64 66
しかし、これは醜いです。
本当にdd
を使用したい場合は、次のabominationを使用して、指定されたバイトの最上位ビットをフリップすることでトリックを実行します。 tr
コマンドの設定を調整して、選択したビットを変更します。
# Preparation
finger > original.txt
BYTE=3
# Here we go...
dd if=original.txt bs=1c 2>/dev/null | ( dd bs=1c count=$((BYTE-1)) ; dd bs=1c count=1 | tr '\000-\377' '\200-\377\000-\177' ; dd bs=1c ) 2>/dev/null > flipped.txt
# Demonstrate the difference (byte 3: 67 → e7)
hexdump -C original.txt | head -1
00000000 4c 6f 67 69 6e 20 20 20 20 20 4e 61 6d 65 20 20 |Login Name |
hexdump -C flipped.txt | head -1
00000000 4c 6f e7 69 6e 20 20 20 20 20 4e 61 6d 65 20 20 |Lo.in Name |
ここに2つのPerl
ワンライナーがあります。最初はファイルbar
をその場で変更します:
Perl -p -0777 -i -e 'substr($_,2,1)^=chr(1<<5)' bar
2番目は、ファイルfoo
を読み取り、bar
を書き込みます
Perl -p -0777 -e 'substr($_,2,1)^=chr(1<<5)' < foo > bar
アプリケーションに適応するには:2はどのバイトを選択します:0..file_length-1、つまり2は3番目のバイトです。 5はフリップするビットを選択します。0〜7、つまり5は6番目のビットです。これは、メモリに収まるファイルに対してのみ機能します。
-p
ファイルを反復処理し、各反復処理の後に出力します-0777
各反復でファイル全体をメモリに読み込みます(したがって、反復は1つだけになります)-e
ループ内で次のPerlコードを実行しますsubstr
インデックス2から始まるファイル内の1文字を選択します^=chr
XOR 1が5シフトした文字、つまり2 ^ 5
この答えは toddkaufmann's の簡略版です。
head
、tail
、xxd
を使用した簡単なソリューション。以下の例では、file.binの最後のバイトの最下位ビットを反転します。
head -c -1 file.bin > flipped.bin
LAST=`tail -c 1 file.bin | xxd -ps`
printf "%02X" $(( $((16#$LAST)) ^ 1 )) | xxd -r -ps >> flipped.bin