Làm cách nào để so sánh các tệp nhị phân trong Linux?


304

Tôi cần so sánh hai tệp nhị phân và nhận đầu ra ở dạng:

<fileoffset-hex> <file1-byte-hex> <file2-byte-hex>

cho mỗi byte khác nhau. Vì vậy, nếu file1.bin

  00 90 00 11

ở dạng nhị phân và file2.bin

  00 91 00 10

Tôi muốn có được một cái gì đó như

  00000001 90 91
  00000003 11 10

Có cách nào để làm điều này trong Linux không? Tôi biết cmp -lnhưng nó sử dụng một hệ thống thập phân cho offset và bát phân cho các byte mà tôi muốn tránh.


9
về cơ bản bạn đang tìm kiếm "nhị phân khác biệt". tôi có thể tưởng tượng một số dòng lệnh xấu xí đáng kinh ngạc với od...
quack quixote

2
@quack quixote: Điều gì xấu xí về một lớp lót? ;)
Bobby

xdelta.org hoạt động khá tốt. Có lẽ nó đáng để xem qua nó.
thatjuan

Vì bạn không thể trả lời câu hỏi này (vì bạn không phải là người dùng), nên tôi sẽ bỏ phiếu để đóng. Một khác biệt nhị phân như được yêu cầu rõ ràng ở đây hoàn toàn không hữu ích và tôi có xu hướng nghĩ rằng bạn muốn thứ gì đó hữu ích, nếu bạn chèn một byte vào đầu tệp thì tất cả các byte có được đánh dấu là khác nhau không? Không biết rằng, điều này chỉ đơn giản là quá mơ hồ.
Evan Carroll

2
@EvanCarroll Nếu bạn nghĩ rằng câu hỏi không đúng chủ đề tại sao bạn trả lời nó?
DavidPostill

Câu trả lời:


174

Điều này sẽ in offset và byte ở dạng hex:

cmp -l file1.bin file2.bin | gawk '{printf "%08X %02X %02X\n", $1, strtonum(0$2), strtonum(0$3)}'

Hoặc làm $1-1để có phần in offset đầu tiên bắt đầu từ 0.

cmp -l file1.bin file2.bin | gawk '{printf "%08X %02X %02X\n", $1-1, strtonum(0$2), strtonum(0$3)}'

Thật không may, strtonum()là dành riêng cho GAWK, vì vậy đối với các phiên bản khác của awk, ví dụ như mawk, bạn sẽ cần sử dụng hàm chuyển đổi bát phân sang thập phân. Ví dụ,

cmp -l file1.bin file2.bin | mawk 'function oct2dec(oct,     dec) {for (i = 1; i <= length(oct); i++) {dec *= 8; dec += substr(oct, i, 1)}; return dec} {printf "%08X %02X %02X\n", $1, oct2dec($2), oct2dec($3)}'

Bẻ ra để dễ đọc:

cmp -l file1.bin file2.bin |
    mawk 'function oct2dec(oct,    dec) {
              for (i = 1; i <= length(oct); i++) {
                  dec *= 8;
                  dec += substr(oct, i, 1)
              };
              return dec
          }
          {
              printf "%08X %02X %02X\n", $1, oct2dec($2), oct2dec($3)
          }'

3
@gertvdijk: strtonumdành riêng cho GAWK. Tôi tin rằng Ubuntu trước đây đã sử dụng GAWK làm mặc định, nhưng đã chuyển sang một số điểm mawk. Trong mọi trường hợp, GAWK có thể được cài đặt và đặt thành mặc định (xem thêm man update-alternatives). Xem câu trả lời cập nhật của tôi cho một giải pháp không yêu cầu strtonum.
Dennis Williamson

Tại sao không chỉ đơn giản là so sánh sha256sum của cả hai tập tin?
Rodrigo

1
@Rodrigo: Điều đó và nhiều phương pháp khác sẽ chỉ hiển thị xem các tệp có khác nhau không. Câu trả lời của tôi đáp ứng yêu cầu của OP để thực sự cho thấy sự khác biệt là gì.
Dennis Williamson

Tất nhiên! Xin lỗi, tôi đã rất lo lắng về vấn đề CỦA TÔI đến nỗi tôi hầu như không đọc được OP. Cảm ơn bạn.
Rodrigo

166

Như ~ quạc chỉ ra:

 % xxd b1 > b1.hex
 % xxd b2 > b2.hex

Và sau đó

 % diff b1.hex b2.hex

hoặc là

 % vimdiff b1.hex b2.hex

70
Trong Bash: diff <(xxd b1) <(xxd b2)nhưng định dạng đầu ra của cái này (hoặc của bạn) không ở đâu gần với những gì OP yêu cầu.
Dennis Williamson

6
với vimdiff, nó sẽ tô màu các byte trong các dòng có hai 'tệp' khác nhau
akira

À, tại sao tôi không nghĩ về điều đó? Và tôi chắc chắn rằng tôi cũng đã sử dụng kỹ thuật này trong quá khứ.
njd

1
Điều này làm việc rất tốt cho tôi (với opendifftrên OS X thay vì vimdiff) - chế độ xem mặc định xxdcung cấp cho công cụ tìm khác biệt theo dõi so sánh từng byte. Với hex (thô) đơn giản phù hợp với cột fold, diffsẽ cố gắng gấp / nhóm các công cụ ngẫu nhiên trong các tệp tôi đang so sánh.
natevw

1
Lệnh này không hoạt động tốt để loại bỏ bổ sung byte, vì mỗi dòng tiếp theo sẽ bị sai lệch và được xem như được sửa đổi bởi diff. Giải pháp là đặt 1 byte trên mỗi dòng và xóa cột địa chỉ theo đề xuất của John Lawrence Aspdentôi .
Ciro Santilli 心 心

98

diff + xxd

Hãy thử diffkết hợp thay thế quá trình zsh / bash sau đây:

diff -y <(xxd foo1.bin) <(xxd foo2.bin)

Ở đâu:

  • -y cho bạn thấy sự khác biệt cạnh nhau (tùy chọn).
  • xxd là công cụ CLI để tạo đầu ra hexdump của tệp nhị phân.
  • Thêm vào -W200để diffđầu ra rộng hơn (200 ký tự trên mỗi dòng).
  • Đối với màu sắc, sử dụng colordiffnhư hình dưới đây.

colordiff + xxd

Nếu bạn colordiff, nó có thể tô màu diffđầu ra, ví dụ:

colordiff -y <(xxd foo1.bin) <(xxd foo2.bin)

Nếu không thì cài đặt qua : sudo apt-get install colordiff.

Đầu ra mẫu:

đầu ra tệp nhị phân trong terminal - diff -y <(xxd foo1.bin) <(xxd foo2.bin) |  đại tá

vimdiff + xxd

Bạn cũng có thể sử dụng vimdiff, vd

vimdiff <(xxd foo1.bin) <(xxd foo2.bin)

Gợi ý:

  • nếu tệp quá lớn, hãy thêm giới hạn (ví dụ -l1000) cho mỗi tệpxxd

11
Lệnh có thể được đơn giản hóa như colordiff -y <(xxd foo1.bin) <(xxd foo2.bin).
golem

3
Nếu bạn không có colordiff, điều này sẽ làm điều tương tự mà không có màu sắc:diff -y <(xxd foo1.bin) <(xxd foo2.bin)
Rock Lee

5
Nếu bạn chỉ muốn biết liệu cả hai tệp có thực sự giống nhau hay không, bạn có thể sử dụng -qhoặc --briefchuyển đổi, điều này sẽ chỉ hiển thị đầu ra khi các tệp khác nhau.
Stefan van den Akker

1
tạo một chức năng xxddiffcho việc này với:xxddiff() ( f() ( xxd "$1" ; ); diff -y <(f "$1") <(f "$2") | colordiff; )
rubo77

2
tuyệt quá! Tuy nhiên, diff -u <(xxd tinga.tgz) <(xxd dec.out.tinga.tgz) | vim - sẽ làm một công việc tốt enoug
ribamar

56

Có một công cụ gọi là DHEX có thể thực hiện công việc và có một công cụ khác gọi là VBinDiff .

Đối với một cách tiếp cận dòng lệnh nghiêm ngặt, hãy thử jojodiff .


8
DHEX thật tuyệt vời khi so sánh nhị phân là những gì bạn muốn làm. Cung cấp cho nó hai tệp và nó đưa bạn đến một cái nhìn so sánh, làm nổi bật sự khác biệt, với khả năng dễ dàng chuyển sang sự khác biệt tiếp theo. Ngoài ra, nó có thể hoạt động với các thiết bị đầu cuối lớn, rất hữu ích trên màn hình rộng.
Marcin

7
Tôi thích VBinDiff. DHEX đang sử dụng CPU ngay cả khi không hoạt động, tôi nghĩ rằng nó đang vẽ lại mọi lúc hoặc mọi thứ. VBinDiff không hoạt động với các thiết bị đầu cuối rộng. Nhưng dù sao địa chỉ cũng trở nên kỳ lạ với các thiết bị đầu cuối rộng, vì bạn có hơn 16 byte mỗi hàng.
Janus Troelsen

1
vbindiff cho phép chúng tôi thực sự chỉnh sửa tập tin, thx!
Sức mạnh Bảo Bình

2
Các tệp nén @DanielBeauyat sẽ hoàn toàn khác sau khi bạn gặp byte khác nhau đầu tiên. Đầu ra không có khả năng hữu ích.
Đánh dấu tiền chuộc

2
@ 1111161171159459134 jdiff là một phần của "bộ" chương trình để đồng bộ hóa và vá các khác biệt được tìm thấy bởi jdiff. Nhưng, như Mark Ransom đã nói, điều đó thường không khôn ngoan đối với các tệp nén; ngoại lệ là các định dạng nén "có thể đồng bộ hóa" (giống như định dạng được tạo bởi gzip --rsyncable), trong đó các khác biệt nhỏ trong các tệp không nén sẽ có tác dụng hạn chế đối với tệp nén.
hmijail

27

Phương thức hoạt động để thêm / xóa byte

diff <(od -An -tx1 -w1 -v file1) \
     <(od -An -tx1 -w1 -v file2)

Tạo một trường hợp thử nghiệm với một lần loại bỏ byte 64:

for i in `seq 128`; do printf "%02x" "$i"; done | xxd -r -p > file1
for i in `seq 128`; do if [ "$i" -ne 64 ]; then printf "%02x" $i; fi; done | xxd -r -p > file2

Đầu ra:

64d63
<  40

Nếu bạn cũng muốn xem phiên bản ASCII của nhân vật:

bdiff() (
  f() (
    od -An -tx1c -w1 -v "$1" | paste -d '' - -
  )
  diff <(f "$1") <(f "$2")
)

bdiff file1 file2

Đầu ra:

64d63
<   40   @

Đã thử nghiệm trên Ubuntu 16.04.

Tôi thích odhơn xxdvì:

  • đó là POSIX , xxdkhông phải (đi kèm với Vim)
  • -Anđể loại bỏ cột địa chỉ mà không có awk.

Lệnh giải thích:

  • -Anxóa cột địa chỉ. Điều này rất quan trọng nếu không tất cả các dòng sẽ khác nhau sau khi thêm / xóa byte.
  • -w1đặt một byte trên mỗi dòng, để diff có thể tiêu thụ nó. Điều quan trọng là phải có một byte trên mỗi dòng hoặc nếu không thì mỗi dòng sau khi xóa sẽ trở nên lệch pha và khác nhau. Thật không may, đây không phải là POSIX, nhưng hiện diện trong GNU.
  • -tx1 là đại diện bạn muốn, thay đổi thành bất kỳ giá trị nào có thể, miễn là bạn giữ 1 byte trên mỗi dòng.
  • -vngăn chặn viết tắt dấu hoa thị *có thể can thiệp vào diff
  • paste -d '' - -tham gia mỗi hai dòng. Chúng tôi cần nó bởi vì hex và ASCII đi vào các dòng liền kề riêng biệt. Lấy từ: https://stackoverflow.com/questions/8987257/concatenating-every-other-line-with-the-next
  • chúng tôi sử dụng dấu ngoặc đơn ()để xác định bdiffthay vì {}giới hạn phạm vi của hàm bên trong f, xem thêm: https://stackoverflow.com/questions/8426077/how-to-define-a-feft-inside-another-feft-in-bash

Xem thêm:


13

Câu trả lời ngắn

vimdiff <(xxd -c1 -p first.bin) <(xxd -c1 -p second.bin)

Khi sử dụng hexdumps và text diff để so sánh các tệp nhị phân, đặc biệt xxd, việc bổ sung và loại bỏ byte trở thành thay đổi trong việc đánh địa chỉ có thể gây khó khăn cho việc xem. Phương thức này báo cho xxd không xuất địa chỉ và chỉ xuất một byte trên mỗi dòng, từ đó hiển thị chính xác byte nào đã được thay đổi, thêm hoặc xóa. Bạn có thể tìm thấy các địa chỉ sau bằng cách tìm kiếm các chuỗi byte thú vị trong một hexdump "bình thường" hơn (đầu ra của xxd first.bin).


(Tất nhiên, người ta có thể sử dụng diffthay vì vimdiff.)
VasyaNovikov

11

Tôi muốn giới thiệu hexdump để chuyển các tệp nhị phân sang định dạng văn bản và kdiff3 để xem khác.

hexdump myfile1.bin > myfile1.hex
hexdump myfile2.bin > myfile2.hex
kdiff3 myfile1.hex myfile2.hex

2
Ngay cả ở đây trong bash kdiff3 <(hexdump myfile1.bin) <(hexdump myfile2.bin)mà không cần phải tạo tập tin myfile1.hexmyfile2.hex.
Hastur

5

Đây hexdifflà một chương trình được thiết kế để làm chính xác những gì bạn đang tìm kiếm.

Sử dụng:

hexdiff file1 file2

Nó hiển thị hex (và ASCII 7 bit) của hai tệp nằm trên tệp kia, với bất kỳ sự khác biệt nào được tô sáng. Nhìn vào man hexdiffcác lệnh để di chuyển trong tệp và đơn giản qsẽ thoát.


4
Nhưng nó làm một công việc khá tệ khi nói đến phần so sánh. Nếu bạn chèn một số byte vào một tệp, nó sẽ đánh dấu tất cả byte sau đó là thay đổi
Murmel

và hexdiff không khả dụng qua apt-get trên Ubuntu 16.4
rubo77

1
@Murmel trong khi tôi đồng ý, không phải đó là những gì đang được hỏi ở đây sao?
Evan Carroll

@EvanCarroll đúng, và do đó tôi đã để lại một bình luận (chỉ) và không downvote
Murmel

Tôi cũng không bỏ phiếu Mick, nhưng tôi đồng ý với bạn và trả lời ở đây superuser.com/a/1373977/11116 vì có vẻ như câu hỏi tồi này sẽ được cải cách hoặc đóng lại.
Evan Carroll

3

Nó có thể không trả lời đúng câu hỏi, nhưng tôi sử dụng điều này để phân biệt nhị phân:

gvim -d <(xxd -c 1 ~/file1.bin | awk '{print $2, $3}') <(xxd -c 1 ~/file2.bin | awk '{print $2, $3}')

Nó in cả hai tệp ra dưới dạng giá trị hex và ASCII , một byte trên mỗi dòng và sau đó sử dụng tiện ích khác của Vim để hiển thị chúng một cách trực quan.


0

dhex http://www.dettus.net/dhex/

DHEX không chỉ là một trình soạn thảo hex khác: Nó bao gồm một chế độ khác, có thể được sử dụng để so sánh dễ dàng và thuận tiện hai tệp nhị phân. Vì nó dựa trên ncurses và có thể sử dụng được, nên nó có thể chạy trên bất kỳ số lượng hệ thống và kịch bản nào. Với việc sử dụng nhật ký tìm kiếm, có thể theo dõi các thay đổi trong các lần lặp khác nhau của các tệp một cách dễ dàng.


Chào mừng bạn đến với SuperUser! Mặc dù phần mềm này có vẻ như có thể giải quyết vấn đề của OP, nhưng quảng cáo thuần túy được tán thành mạnh mẽ trên mạng Stack Exchange. Nếu bạn được liên kết với trình soạn thảo của phần mềm này, vui lòng tiết lộ sự thật này. Và cố gắng viết lại bài đăng của bạn để nó trông giống như một quảng cáo. Cảm ơn bạn.
Nathan.Eilisha Shiraini

Tôi không liên kết với dhex dưới bất kỳ hình thức nào. Tôi đã sao chép mô tả của tác giả vào bài viết vì có giới hạn độ dài bài tối thiểu
Vincent Vega

Đã được đề cập tại: superuser.com/a/125390/128124
Ciro Santilli 新疆 心 心

0

Bạn có thể sử dụng gvimdiff công cụ được bao gồm trong vim-gui-chung gói

sudo apt-get cập nhật

sudo apt-get install vim-gui-common

Sau đó, bạn có thể so sánh 2 tệp hex bằng các lệnh sau:

ubuntu> gvimdiff <hex-file1> <hex-file2>

Tất cả. Mong tha giúp!


0

Công cụ phân tích phần sụn binwalkcũng có tính năng này như một tính năng thông qua tùy chọn dòng lệnh -W/--hexdump cung cấp các tùy chọn như chỉ hiển thị các byte khác nhau:

    -W, --hexdump                Perform a hexdump / diff of a file or files
    -G, --green                  Only show lines containing bytes that are the same among all files
    -i, --red                    Only show lines containing bytes that are different among all files
    -U, --blue                   Only show lines containing bytes that are different among some files
    -w, --terse                  Diff all files, but only display a hex dump of the first file

Trong ví dụ của OP khi làm binwalk -W file1.bin file2.bin:

binwalk -W file1.bin file2.bin



-2

Sản phẩm nguồn mở trên Linux (và mọi thứ khác) là Radare cung cấp radiff2rõ ràng cho mục đích này. Tôi đã bỏ phiếu để đóng cái này vì bản thân tôi và những người khác có cùng một câu hỏi, trong câu hỏi bạn hỏi

cho mỗi byte khác nhau

Điều đó thật điên rồ. Bởi vì như đã hỏi, nếu bạn chèn một byte ở byte đầu tiên trong tệp, bạn sẽ thấy mỗi byte tiếp theo là khác nhau và do đó diff sẽ lặp lại toàn bộ tệp, cho sự khác biệt thực tế của một byte.

Hơi thực tế hơn một chút radiff -O. Cái -Onày dành cho "" Do mã khác với tất cả các byte thay vì chỉ các byte opcode cố định ""

0x000000a4 0c01 => 3802 0x000000a4
0x000000a8 1401 => 3802 0x000000a8
0x000000ac 06 => 05 0x000000ac
0x000000b4 02 => 01 0x000000b4
0x000000b8 4c05 => 0020 0x000000b8
0x000000bc 4c95 => 00a0 0x000000bc
0x000000c0 4c95 => 00a0 0x000000c0

Giống như IDA Pro, Radare là công cụ chính để phân tích nhị phân, bạn cũng có thể hiển thị delta khác với -dhoặc hiển thị các byte được tháo rời thay vì hex bằng -D.

Nếu bạn đang hỏi những loại câu hỏi này, hãy xem

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.