Contents

在Linux下比较二进制文件

1. 概述

在本文中,我们将讨论在 Linux 中比较二进制文件的不同方法。在调查不同文件以进行数据恢复、逆向工程和其他编程问题时,我们可能需要它。

2. 问题陈述

**为了举例说明本文的问题,我们首先需要两个二进制文件。然后,我们将比较这两个二进制文件。*我们可以通过运行带有两个选项的echo 命令来生成它们。标志-n防止输出尾随换行符。此外,-e*标志使用十六进制值 ( \xHH ) 来获取我们想要在文件中的数据:

$ echo -n -e \\x41\\x2e\\x42\\x2e\\x43\\x2e\\x44\\x2e > binary_file_1.bin
$ echo -n -e \\x41\\x2e\\x41\\x2e\\x42\\x2e\\x42\\x2e > binary_file_2.bin

我们需要双反斜杠来转义反斜杠本身。

使用前面的命令,我们创建了两个二进制文件binary_file_1.binbinary_file_2.bin。**在第一个中,我们存储了字符串“ABCD”,在第二个中,我们存储了字符串“AABB”。**因此,它们在三个字符上有所不同:“BCD”与“ABB”。

在此示例中,了解文件的内容将有助于讨论并简化对工具的理解。然而,在真实案例中,内容却是未知的:确实是我们想要发现的!

3. 解决方案

一般来说,我们可以将问题分成两部分。**第一部分包括将二进制信息转换为我们可以比较的有意义的东西。**为此,我们将使用od 等工具。xxd 或 hexdump

**问题的第二部分实际上是比较我们之前获得的信息。**我们可以使用多种工具,例如diffvimdiff 。我们在前三种方法中展示了这些工具,尽管我们可以在其他组合中使用它们来进一步自定义输出和格式。

**提出的最后一个和第四个解决方案颠倒了这个过程。它首先比较文件,然后将二进制信息转换为字符串。此解决方案的工具是cmpgawk

3.1. 带差异的od

** od命令(代表八进制转储)可用于将二进制文件转换为十六进制文件。**因此,我们可以继续处理我们的两个文件:

$ od -tx1 -v binary_file_1.bin > hexa_file_1.hd 
$ od -tx1 -v binary_file_2.bin > hexa_file_2.hd 

我们现在有两个十六进制文件,由我们的二进制文件创建。-v标志可防止行抑制的星号重复(这可能会导致diff出现问题)。

** od命令与*-tx1标志一起使用**以指定十六进制 ( x )的格式(使用-t请求),每个块只有一个 ( 1 ) 字节。其他常见选项是-tx2*,它以十六进制格式为每个块输出两个字节并恢复每个块中的字节顺序,以及*-to1*,它以八进制格式为每个块输出一个字节。

如果我们期望添加和/或删除字节,我们还可以使用其他有用的标志来改进格式。其中包括-An,它删除地址列,和-w1 ,它每行只放置一个字节(用于在使用diff时避免一个阶段 )。

一旦我们有了十六进制文件,我们可以将它们与diff进行比较:

$ diff hexa_file_1.od hexa_file_2.od
1c1
< 0000000 41 2e 42 2e 43 2e 44 2e
---
> 0000000 41 2e 41 2e 42 2e 42 2e

通过使用从一个命令到另一个命令的输入重定向,我们可以运行这两个命令而无需创建新文件。为了说明这一点并显示*-tx2*标志,我们有另一个包含两个功能的示例:

$ diff <(od -tx2 -v binary_file_1.bin) <(od -tx2 -v binary_file_2.bin)
1c1
< 0000000 2e41 2e42 2e43 2e44
---
> 0000000 2e41 2e41 2e42 2e42

请注意,虽然我们得到相同的信息,但每个块的两个字节的字节是反转的!

3.2. 带差异的十六进制转储

在我们使用输入重定向的最后一个片段之后,我们可以结合diffhexdump来比较二进制文件

$ diff <(hexdump binary_file_1.bin) <(hexdump binary_file_2.bin)
1c1
< 0000000 2e41 2e42 2e43 2e44 
---
> 0000000 2e41 2e41 2e42 2e42 

结果与之前的解决方案相同,显示了这种方法的一致性。

diff的一个常见选项是标志*-y*(或更长的版本*–side-by-side*),它显示两个文件,一个并排显示,提高对多行文件的理解:

$ diff -y <(hexdump binary_file_1.bin) <(hexdump binary_file_2.bin)
0000000 2e41 2e42 2e43 2e44 | 0000000 2e41 2e41 2e42 2e42 
0000008                       0000008

3.3. 有差异的xxd

我们也可以用xxd替换hexdump(或od):

$ diff -y <(xxd binary_file_1.bin) <(xxd binary_file_2.bin)
00000000: 412e 422e 432e 442e A.B.C.D. | 00000000: 412e 412e 422e 422e A.A.B.B.

这导致另一个与以前不同的输出。但是,通过检查,我们可以检查两个字节块中的顺序是否已反转:使用hexdump,我们有2e-41,而使用xxd,我们有41-2e这被称为字节序 ,它是hexdumpxxd之间的区别之一。

我们可以看到,在每个十六进制字符串之后,我们还获得了开始文本的 ASCII 表示。这可以通过hexdump中的-C*标志来实现。*

我们可以用vimdiff替换diff来导航文件以便于比较(在这个和所有以前的解决方案中):

$ vimdiff <(xxd binary_file_1.bin) <(xxd binary_file_2.bin)

3.4. 带有gawkcmp

在最后一个解决方案中,我们首先使用cmp工具逐字节比较两个二进制文件

$ cmp -l binary_file_1.bin binary_file_2.bin
3 102 101
5 103 102
7 104 102

正如我们所料,这两个文件在三个位置不同。我们使用*-l标志来显示文件不同的地方,因为cmp*的基本模式是仅说明文件是否不同。

但是,输出是字节信息,处理十六进制信息比较容易。因此,我们可以使用gawk函数将第二列和第三列转换为十六进制

$ cmp -l binary_file_1.bin binary_file_2.bin | gawk '{printf "%08X %02X %02X\n", , strtonum(0), strtonum(0)}'
00000003 42 41
00000005 43 42
00000007 44 42

3.5. 选择哪种解决方案?

正如我们所看到的,不同解决方案的结果是等效的,并且返回相似的结果。因此,我们应该根据两个主要因素进行选择:我们的系统中是否安装了所需的工具以及所需的输出格式。