如何在Linux中比较二进制文件?


303

我需要比较两个二进制文件并以以下形式获取输出:

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

对于每个不同的字节。所以如果file1.bin

  00 90 00 11

以二进制形式和file2.bin

  00 91 00 10

我想得到像

  00000001 90 91
  00000003 11 10

在Linux中有没有办法做到这一点?我知道,cmp -l但是它使用十进制表示偏移量,使用八进制表示字节,我想避免这种情况。


9
您基本上是在寻找“二进制差异”。我可以想象有一些令人毛骨悚然的丑陋命令行一号线与od……
庸医吉x德

2
@quack quixote:单缸飞机有什么丑陋?;)
Bobby 2010年

xdelta.org运作良好。也许值得一看。
thatjuan 2013年

因为您无法回答这个问题(因为您不是用户),所以我投票关闭。此处明确要求的二进制diff根本没有用,我倾向于认为您想要一些有用的东西,如果在文件的开头插入一个字节,应该将所有字节标记为不同吗?不知道这一点,这太含糊了。
埃文·卡罗尔

2
@EvanCarroll如果您认为问题不重要,为什么要回答这个问题?
DavidPostill

Answers:


174

这将以十六进制打印偏移量和字节:

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

$1-1将第一个打印的偏移量从0开始。

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

不幸的是,strtonum()它特定于GAWK,因此对于其他版本的awk(例如mawk),您将需要使用八进制到十进制的转换函数。例如,

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)}'

出于可读性而细分:

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:strtonum特定于GAWK。我相信Ubuntu以前曾使用GAWK作为默认设置,但在某些时候切换到mawk。无论如何,都可以安装GAWK并将其设置为默认值(另请参见man update-alternatives)。请参阅更新后的答案,以获取不需要的解决方案strtonum
丹尼斯·威廉姆森

为什么不简单地比较两个文件的sha256sum?
罗德里戈

1
@Rodrigo:该方法以及其他各种方法将仅显示文件是否不同。我的回答满足了OP的要求,以实际显示出差异。
丹尼斯·威廉姆森

当然!抱歉,我非常担心自己的问题,以至于我几乎没有阅读过OP。谢谢。
罗德里戈

165

正如〜quack指出的那样:

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

接着

 % diff b1.hex b2.hex

要么

 % vimdiff b1.hex b2.hex

70
在Bash中:diff <(xxd b1) <(xxd b2)但此(或您自己)的输出格式与OP要求的格式相去甚远。
丹尼斯·威廉姆森

6
使用vimdiff,它将为两个“文件”不同的行中的字节着色
akira 2010年

噢,我为什么没想到呢?而且我敢肯定,我过去也曾经使用过这种技术。
njd

1
这对我来说非常有效(opendiff在OS X上代替vimdiff),默认视图xxd提供了使diff引擎按字节进行比较的正常轨道。使用普通(原始)十六进制仅与进行列拟合folddiff将尝试折叠/分组我正在比较的文件中的随机内容。
natevw 2014年

1
此命令对于删除字节加法效果不佳,因为后面的每一行都将错位并被修改diff。解决方法是每行放置1个字节,并删除John Lawrence Aspden提出的地址列。
Ciro Santilli新疆改造中心法轮功六四事件

97

diff + xxd

尝试diff以下zsh / bash进程替换的组合:

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

哪里:

  • -y 并排显示差异(可选)。
  • xxd 是用于创建二进制文件的十六进制转储输出的CLI工具。
  • 添加-W200diff用于更宽的输出(每行的200个字符)。
  • 对于颜色,请colordiff如下所示使用。

colordiff + xxd

如果您拥有colordiff,它可以使diff输出着色,例如:

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

否则通过以下方式安装sudo apt-get install colordiff

样本输出:

终端中的二进制文件输出-diff -y <(xxd foo1.bin)<(xxd foo2.bin)|  色差

vimdiff + xxd

您也可以使用vimdiff,例如

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

提示:

  • 如果文件太大,-l1000则为每个文件添加限制(例如)xxd

11
命令可以简化为colordiff -y <(xxd foo1.bin) <(xxd foo2.bin)
golem

3
如果您没有colordiff,这将在没有颜色的情况下执行相同的操作:diff -y <(xxd foo1.bin) <(xxd foo2.bin)
Rock Lee

5
如果只想知道两个文件是否实际上相同,则可以使用-q--brief开关,仅当文件不同时才显示输出。
Stefan van den Akker

1
xxddiff为此创建一个函数:xxddiff() ( f() ( xxd "$1" ; ); diff -y <(f "$1") <(f "$2") | colordiff; )
rubo77 '16

2
大!仍然diff -u <(xxd tinga.tgz) <(xxd dec.out.tinga.tgz) | vim - 会做得很好
ribamar

56

有一个名为DHEX的工具可以完成这项工作,还有另一个名为VBinDiff的工具。

对于严格的命令行方法,请尝试jojodiff


8
DHEX很棒,比较二进制文件是您想要做的。将其馈入两个文件,即可直接进入比较视图,突出显示差异,并轻松移至下一个差异。它还能够与大型终端一起使用,这在宽屏显示器上非常有用。
Marcin

7
我更喜欢VBinDiff。DHEX即使在空闲时也使用CPU,我认为它一直都在重绘。VBinDiff不适用于宽终端。但是,无论如何,地址变得很奇怪,因为终端的行宽很大,因为每行有16个以上的字节。
Janus Troelsen,2012年

1
vbindiff让我们实际编辑文件,谢谢!
Aquarius Power

2
遇到第一个不同的字节后,@ DanielBeauyat的压缩文件将完全不同。输出不太可能有用。
Mark Ransom

2
@ 1111161171159459134 jdiff是程序“套件”的一部分,用于同步和修补jdiff发现的差异。但是,正如Mark Ransom所说,对于压缩文件来说,这通常是不明智的。唯一的例外是“可同步”的压缩格式(例如gzip --rsyncable产生的格式),其中未压缩文件中的细微差异应该对压缩文件的影响有限。
hmijail '16

27

适用于字节添加/删除的方法

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

删除一个字节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

输出:

64d63
<  40

如果您还想查看字符的ASCII版本:

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

bdiff file1 file2

输出:

64d63
<   40   @

在Ubuntu 16.04上测试。

我喜欢odxxd,因为:

  • 是POSIXxxd不是(Vim附带)
  • -An没有删除地址栏awk

命令说明:

也可以看看:


13

简短答案

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

当使用hexdumps和text diff比较二进制文件时,尤其是xxd字节的增加和减少会导致寻址移位,这可能使您很难看到。此方法告诉xxd不输出地址,并且每行仅输出一个字节,从而准确显示更改,添加或删除的字节。您可以稍后在更“正常”的十六进制转储(的输出xxd first.bin)中搜索有趣的字节序列,以找到地址。


(当然,可以使用diff代替vimdiff。)
VasyaNovikov

11

我建议使用hexdump将二进制文件转储为文本格式,使用kdiff3将其差异查看。

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

2
即使在这里kdiff3 <(hexdump myfile1.bin) <(hexdump myfile2.bin),也无需创建文件myfile1.hex和文件myfile2.hex
Hastur

5

hexdiff程序旨在完全满足您的需求。

用法:

hexdiff file1 file2

它将两个文件的十六进制(和7位ASCII)显示在另一个文件的上方,并突出显示所有差异。查看在man hexdiff文件中四处移动的命令,然后一个简单的命令q退出。


4
但是,在比较部分方面做得很糟糕。如果您在文件中插入一些字节,它将随后将所有字节标记为更改
Murmel

并且hexdiff在Ubuntu 16.4上无法通过apt-get获得
rubo77's

1
我同意@Murmel,这不是在问什么吗?
埃文·卡罗尔

@EvanCarroll是对的,因此我只发表了评论,而没有拒绝
投票

我也没有否决Mick,但我同意您的意见,并在此处回答了superuser.com/a/1373977/11116,因为这个坏问题似乎很可能会得到解决或解决。
埃文·卡罗尔

3

它可能不能严格回答这个问题,但是我用它来区别二进制文件:

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

它将两个文件以十六进制和ASCII值打印出来,每行一个字节,然后使用Vim的diff工具以可视方式呈现它们。


0

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

DHEX不仅仅只是另一个十六进制编辑器:它包括diff模式,可用于轻松方便地比较两个二进制文件。由于它基于ncurses并且具有主题性,因此它可以在任何数量的系统和方案上运行。利用搜索日志,可以轻松跟踪文件不同迭代中的更改。


欢迎来到超级用户!尽管此软件看起来可以解决OP的问题,但是在Stack Exchange网络上强烈反对纯广告。如果您隶属于该软件的编辑器,请披露此事实。并尝试重写您的帖子,使其看起来不像是商业广告。谢谢。
Nathan.Eilisha Shiraini

我与dhex无关。我将作者的描述复制到帖子中,因为存在最小帖子长度限制
Vincent Vega

已经在以下
网址

0

您可以使用vim-gui-common软件包中包含的gvimdiff工具

sudo apt-get更新

须藤apt-get install vim-gui-common

然后,您可以使用以下命令比较2个十六进制文件:

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

Tha的全部。希望能有所帮助!


0

固件分析工具binwalk-W/ --hexdump命令行选项也具有此功能,该选项提供诸如仅显示不同字节的选项:

    -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

在OP的示例中,执行binwalk -W file1.bin file2.bin以下操作时:

binwalk -W file1.bin file2.bin



-2

Linux(以及其他所有产品)上的开源产品是Radare,它radiff2为此提供了明确的支持。我投票决定将其关闭,因为我和其他人在您提出的问题中存在相同的问题

对于每个不同的字节

那太疯狂了。因为按照要求,如果在文件的第一个字节插入一个字节,则会发现随后的每个字节都不同,因此差异将重复整个文件,实际差值为一个字节。

稍微实用一些radiff -O。该-O是“”别代码的所有字节而不是只是固定的操作码字节版本比较“”

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

与IDA Pro一样,Radare是二进制分析的主要工具,您也可以使用来显示增量差异-d,或使用来显示反汇编的字节而不是十六进制-D

如果您仍在问这些问题,请查看

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.