Chỉ thay đổi một bit trong tệp


9

Tôi phải kiểm tra hàm băm và tôi chỉ muốn thay đổi một bit của một tệp cụ thể.

Tôi đã thử với lệnh dd. Điều đó hoạt động, nhưng tôi chỉ có thể thay đổi toàn bộ một byte và không chỉ một chút.

sudo dd if=/dev/zero of=/file.bin bs=1 seek=10 count=1 conv=notrunc

Tôi cũng đã thử lệnh sed với regex, nhưng vì tôi không biết nội dung của tệp, tôi không thể thay đổi "a" thành "b".

Có ai biết một lệnh để làm điều này?


1
Nếu bạn có thể tìm thấy một ký tự chữ thường (ascii hoặc byte đơn utf8) và chuyển đổi sang chữ hoa hoặc ngược lại. Sau đó, đây là một thay đổi 1 bit. Đây không phải là một giải pháp rất tốt do đó chỉ là một nhận xét.
ctrl-alt-delor

Có lẽ đó là lựa chọn tốt nhất, nhưng tôi chỉ có thể thay đổi lần xuất hiện đầu tiên chứ? Và tôi có thể nhận được một kết quả trong trường hợp thành công / không tìm thấy? Có lẽ trực tiếp với mặt nạ XOR trên tệp?
Kantium

Làm thế nào để bạn xác định bit nào để thay đổi? Là mục tiêu của bạn để chuyển một chút ở một độ lệch cụ thể ? Và bạn có thay đổi 0 thành 1 và 1 thành 0, hoặc (nói) bạn có luôn đặt nó thành 1 không? Cuối cùng: Tập tin chứa loại dữ liệu nào? Nó có thể là "nhị phân", tức là bao gồm các byte null?
alexis

Lý tưởng nhất là chuyển một bit ngẫu nhiên hoặc cố định là tuyệt vời, nhưng nếu tôi có thể buộc một bit về 0 hoặc một cũng tốt cho tôi. Và vâng, đó là một tệp nhị phân
Kantium

1
Tôi chỉ cần viết một chương trình để đọc byte chứa vị trí bit đã chọn, xây dựng một byte khác nhau chỉ trong một bit và viết nó ra. Vì độ dài tệp không thay đổi, bạn chỉ cần đọc và ghi một byte đó.
alexis

Câu trả lời:


3

Vì tệp có thể chứa null, các bộ lọc hướng văn bản sedsẽ bị lỗi. Nhưng bạn có thể sử dụng ngôn ngữ lập trình có thể xử lý null, như perlhoặc python. Đây là một giải pháp cho Python 3. Đó là một vài dòng dài hơn mức cần thiết, cho khả năng đọc.

#!/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()

Lưu nó trong một tệp (ví dụ bitflip:), làm cho nó có thể thực thi được và chạy nó với tên tệp để sửa đổi và bù theo bit . Lưu ý rằng nó sửa đổi các tập tin tại chỗ. Chạy nó hai lần với cùng một độ lệch và bạn sẽ khôi phục tệp của mình.


Hoạt động như một bùa mê và thật thông minh
Kantium

1
Điều này không hoạt động nếu chạy trong Python2 (Tác giả nên sử dụng / usr / bin / env python3 cho rõ ràng! Tạo tệp với 00000 (ascii). Thay đổi bit 2. Đầu ra chỉ nên thay đổi một ký tự nhưng thay đổi 4. Đảm bảo chạy trong Python 3 chứ không phải Python 2.
Jason Baumgartner

Cảm ơn lời đề nghị, tôi đã thay đổi shebang. (Văn bản đã nói rằng giải pháp là "cho Python 3", nhưng điều này tốt hơn.)
alexis

3

Tôi không nghĩ rằng có một lệnh duy nhất. Đây là một tập lệnh đơn giản, lưu nó thành " 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;

kiểm tra:

$ echo abb | ~/bin/flip-bit.pl 2 0 | od -xa
0000000      6261    0a63                                                
       a   b   c  nl                                                

điều này đã lật bit thứ tự thấp (0) của ký tự thứ ba, thay đổi 'b' thành 'c'.

Là một dòng lệnh đơn:

perl -e '$byte=shift(@ARGV);$bit=shift(@ARGV);undef $/; $file=<>; substr($file,$byte,1) = substr($file,$byte,1) ^ chr(1<<$bit); print $file'

Gợi ý: Bạn cần chuyển hướng stdoutvào một tệp để lưu kết quả. Ví dụ:perl flipbit.pl 1000000 1 data.tgz > data_corrupt.tgz
Boris Däppen

2

Cuối cùng tôi tìm thấy một giải pháp với xxddd.

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

Nhưng điều này thật xấu xí.


Tôi đã gặp lỗi bash cho một byte khi dẫn '0' vì vậy tôi đã thay đổi phần XOR thànhecho -e "\x$((${a#0}^${b}))"
MattSmith

Xin lỗi, nó phải là một0x${a}
MattSmith

1

Nếu bạn thực sự muốn sử dụng dd, đây là một sự gớm ghiếc sẽ thực hiện thủ thuật bằng cách lật bit cao nhất trong byte đã cho. Điều chỉnh cài đặt cho trlệnh để thay đổi bit đã chọn.

# 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  |

0

Giải pháp đơn giản sử dụng head, tail, xxd. Ví dụ bên dưới lật bit đáng kể nhất trong byte cuối cùng của 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

0

Đây là hai perllớp lót. Đầu tiên thay đổi tập tin bartại chỗ:

perl -p -0777 -i -e 'substr($_,2,1)^=chr(1<<5)' bar

Thứ hai đọc tập tin foovà viếtbar

perl -p -0777 -e 'substr($_,2,1)^=chr(1<<5)' < foo > bar

Để thích ứng với ứng dụng của bạn: 2 chọn byte nào: 0..file_length-1, tức là 2 là byte thứ 3. 5 chọn bit nào để lật: 0-7, tức là 5 là bit thứ 6. Điều này sẽ chỉ làm việc cho các tập tin phù hợp với bộ nhớ.

Giải trình

-pLặp lại qua tệp, in sau mỗi lần lặp
-0777đọc toàn bộ tệp vào bộ nhớ trên mỗi lần lặp (vì vậy sẽ chỉ có một lần lặp)
-echạy mã perl sau trong vòng lặp,
substrchọn một ký tự trong tệp bắt đầu từ chỉ mục 2
^=chrXOR mà ký tự đó 1 thay đổi 5 lần tức là 2 ^ 5

Câu trả lời này là một phiên bản đơn giản hóa của babkaufmann

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.