Как сравнить бинарные файлы в Linux

Как проверить, совпадают ли два бинарных файла Linux? Если это исполняемые файлы, любые различия могут означать нежелательное или злонамеренное поведение. Вот самый простой способ проверить, отличаются ли они.
Сравнение бинарных файлов
В Linux есть множество способов сравнения и анализа текстовых файлов. Команда diff сравнит два файла и выделит различия. Он может даже предоставить несколько строк по обе стороны от изменений, чтобы обеспечить некоторый контекст вокруг измененных строк. А команда colordiff добавляет цвет, чтобы сделать визуальный анализ различий еще проще.
Разработчики и авторы используют diff , чтобы выделить различия между различными версиями файлов исходного кода программы или черновиками текстов. Это быстро и просто, и вам не нужны какие-либо технические навыки, чтобы увидеть различия между строками текста.
В мире бинарных файлов все не так просто. Двоичные файлы не состоят из простого текста. Они состоят из множества байтов, содержащих числовые значения. Если это сжатый файл, такой как архив TAR или файл ZIP, эти значения представляют собой сжатые файлы, которые хранятся внутри файла архива, а также таблицы символов, необходимые для распаковки и извлечения файлов.
Если двоичный файл является исполняемым файлом, числовые значения байтов файла интерпретируются как такие вещи, как инструкции машинного кода для ЦП, метаданные, метки или закодированные данные. Изменения в двоичном файле или файле библиотеки могут привести к различиям в поведении, когда двоичный файл выполняется или используется другим приложением.
Дату и время создания или изменения файла легко подделать. Это означает, что может быть две версии файла с одинаковым именем, размером файла (если изменения заменяют существующее содержимое байт за байтом) и отметками даты. И все же, один из файлов мог быть изменен.
Алгоритмы безопасного хеширования
Алгоритм безопасного хеширования — это математический алгоритм. Он создает 64-битное значение, сканируя все байты в файле и применяя к ним математическое преобразование для создания хеш-значения. В любой день один и тот же файл всегда будет производить один и тот же хэш. Даже разница в один байт приведет к совершенно другому хешу.
Вы часто будете видеть хэш файла, отображаемый на его странице загрузки. Вы должны сгенерировать хэш для файла после его загрузки. Если он отличается от хеша, отображаемого на веб-странице, вы знаете, что файл скомпрометирован. Он либо был подделан и заменен подлинным файлом, чтобы заставить людей загружать испорченный файл, либо он был поврежден при передаче.
На нашем тестовом компьютере у нас есть две копии одного и того же файла, общей библиотеки. Файлы были переименованы, чтобы они могли находиться в одном каталоге. Теоретически эти файлы должны быть одинаковыми. В конце концов, они должны быть одной и той же версией общей библиотеки.

Файлы имеют одинаковый размер, одинаковые отметки даты и времени. Стороннему наблюдателю они покажутся одинаковыми. Давайте воспользуемся командой sha256sum и сгенерируем хэш для каждого файла.

Хэши совершенно разные, что явно указывает на наличие различий между двумя файлами. Если веб-сайт показывает хэш подлинного файла, вы можете отбросить файл, который не соответствует.
Нахождение различий
Если вы хотите посмотреть на изменения, есть способы сделать это тоже. Вам не нужно ни уметь декомпилировать файл, ни разбираться в ассемблере или машинном коде, чтобы увидеть изменения. Чтобы понять, что эти изменения значат и какова их цель, конечно, потребуются более глубокие технические знания. Но простое знание того, насколько существенны изменения, может указывать на то, что произошло с файлом.
Если мы используем diff для двух двоичных файлов, мы получим немного неутешительный ответ.

Мы уже знали, что файлы были разными. Давайте попробуем cmp .

Это говорит нам немного больше. Первым байтом, который отличается между двумя файлами, является байт номер 13451. То есть, считая от начала двоичного файла, байт 13451 отличается в двух двоичных файлах. Итак, 13451 — это смещение первого отличия от начала файла.
Просто случайно в файле будут байты, содержащие шестнадцатеричное значение 0x10. Это значение, которое Linux использует в текстовых файлах в качестве символа конца строки. Команда cmp обнаружила 131 байт с этим значением между началом двоичного файла и местоположением первой разницы. Поэтому он думает, что находится в строке 132. В данном контексте это действительно ничего не значит.
Если мы добавим параметр -l (подробный), мы начнем получать полезную информацию.

Перечислены все отличающиеся байты. Отображается номер байта или смещение, значение из первого файла и значение из второго файла, по одному байту на строку вывода.
Значения байтов отображаются в восьмеричном формате вместо обычного шестнадцатеричного формата, используемого для двоичных файлов. Тем не менее, мы узнали кое-что еще. Все измененные байты находятся в одной непрерывной последовательности. Их смещения увеличиваются на единицу для каждого байта.
Инструмент hexdump создаст дамп двоичного файла в окно терминала. Если мы используем параметр -C (канонический), вывод будет перечислять в каждой строке смещение, значения 16 байтов по этому смещению и, если есть, ASCII-представление значений байтов. .

Мы можем использовать выходные данные hexdump в качестве входных данных для diff , позволяя diff работать так, как если бы он читал два текстовых файла.

diff находит отличающиеся строки и показывает шестнадцатеричные значения байтов из первого файла над значениями из второго файла. Смещение первой строки равно 0x3480 или 13440 в десятичном формате. Ранее cmp сообщил нам, что первое изменение произошло в байте 13451, то есть 0x348B. Это действительно соответствует тому, что мы видим здесь.
Вывод из diff состоит из двухбайтовых блоков. Первая пара байтов — это байты 0 и 1 по смещению 0x3480, второй блок содержит байты 2 и 3 по смещению. Блок 6 будет содержать байты 0xA и 0xB или 10 и 11 в десятичном виде. Это байты 13450 и 13451. И мы видим, что это первые отличающиеся байты. Первые пять пар байтов одинаковы в обоих файлах.
Однако, поскольку diff считает от нуля, то, что cmp вызывает 13451, будет байтом 13540 для diff . И чтобы сделать ситуацию еще более запутанной, порядок байтов в каждом двухбайтовом блоке меняется на противоположный с помощью diff . На самом деле байты перечислены в следующем порядке: 1 и 0, 3 и 2, 5 и 4, 7 и 6 и так далее.
Команда также требует больших вычислительных ресурсов — два шестнадцатеричных дампа и diff одновременно — особенно если сравниваемые файлы большие.
Но если hexdump -C может отправить ASCII-версию двоичного файла в окно терминала, почему бы нам не перенаправить вывод в текстовые файлы, а затем сравнить эти два текстовых файла с diff ?

Разница между двумя файлами отображается в двух коротких отрывках. Рядом с ними есть ASCII-представление. Для каждого различия между файлами будет пара извлечений. В этом примере есть только одно отличие.
Все это очень хорошо, но разве не было бы здорово, если бы было что-то, что делало бы все это за вас?
VBinDiff
Программу VBinDiff можно установить из обычных репозиториев для всех основных дистрибутивов. Чтобы установить его в Ubuntu, используйте эту команду:

В Fedora вам нужно ввести:

Пользователям Manjaro необходимо использовать pacman .

Чтобы использовать программу, передайте имена двух двоичных файлов в командной строке.

Откроется терминальное приложение, показывающее оба файла в режиме прокрутки.

Для перемещения по файлам можно использовать колесо прокрутки мыши или клавиши «Стрелка вверх», «Стрелка вниз», «Домой», «Конец», «PageUp» и «PageDown». Оба файла будут прокручиваться.
Нажмите клавишу «Ввод», чтобы перейти к первому различию. Разница выделена в обоих файлах.

Если бы различий было больше, нажатие «Enter» отобразило бы следующее различие. Нажатие «q» или «Esc» приведет к выходу из программы.
Какая разница?
Если вы работаете на чужом компьютере и вам не разрешено устанавливать какие-либо пакеты, вы можете использовать cmp , diff и hexdump . Если вам нужно зафиксировать выходные данные для дальнейшей обработки, вы также можете использовать эти инструменты.
Но если вам разрешено устанавливать пакеты, VBinDiff упростит и ускорит ваш рабочий процесс. И на самом деле, использование VBinDiff с одним бинарным файлом — это простой и удобный способ просматривать бинарные файлы, что является приятным бонусом.
Как с помощью командной строки сравнить два текстовых или бинарных файла
Б ывают случаи, когда у пользователей возникает необходимость проверить два файла на идентичность. Чаще всего с подобной задачей сталкиваются начинающие веб-разработчики и программисты. Отыскивать несоответствия в одинаковых с виду файлах приходится редакторам, корректорам и прочим специалистам, работающим с текстовыми данными.
По идее для этих целей лучше всего использовать специальные утилиты, например WinMerge, но файлы также можно сравнивать с помощью самой обыкновенной командной строки . В командной оболочке всех версий Windows имеется замечательная команда FC. Она позволяет сравнивать между собой любые файлы, причём как текстовые, так и бинарные. Синтаксис этой команды очень прост и выглядит он следующим образом:
FC /ключ [полный путь к первому файлу] [полный путь ко второму файлу]
Список доступных ключей можно просмотреть, набрав и выполнив в консоли CMD команду FC /? . Справка даётся на русском языке, так что вы без труда разберетесь, что к чему.

А теперь немного практики. Допустим, у вас есть два файла с кодом PHP и в одном из них предположительно имеются некие различия. Скрипты PHP это обычные текстовые файлы , поэтому в данном случае будем использовать ключ L предназначенный для сравнения текстовых документов в кодировке ASCII. Если скрипт содержит кириллицу, не забудьте перед выполнением команды сравнения выставить в консоли кодировку 1251, иначе на выходе вы получите крякозябры. Смена кодировки выполняется командой chcp 1251 .

Затем сравниваем файлы:
FC /L D:/1.php D:/2.php

Различия между файлами выводятся в следующем порядке. Сначала идёт имя первого файла, затем строка, в которой было найдено несовпадение. За ним идёт имя второго файла и точно также указывается различающаяся строка. Если программа находит ещё несколько несоответствий в других строках, всё повторяется. В общей сложности утилита может обнаружить до 100 различий, такое ограничение имеет используемый командой fc внутренний буфер.
При поиске несоответствий в бинарных файлах используется ключ B. При этом сравнение производится побайтово. В принципе, таким способом можно сравнивать любые файлы, ведь все они по сути двоичны, просто при работе с текстовыми форматами FC может ограничиться информацией какой из сравниваемых объектов длиннее и на этом завершить свою работу.
FC /B D:/1.exe D:/2.exe
В данном примере сравниваются два исполняемых файла. Результат такого сравнения будет выглядеть примерно следующим образом:
00000040: 56 BA
00000050: 65 68
00000060: 43 72
00000070: 6U 0A

Если вы раньше никогда не имели дела с шестнадцатеричными редакторами, разобраться со всем этим нагромождением символов будет непросто. В общем так, каждая выведенная в консоли строка это найденное различие. Символы до двоеточия указывают на смещение от начала файла, первое двухзначное число это соответствующий смещению байт в первом файле, второе двухзначное число — соответствующий смещению байт во втором файле.

Какими ещё полезными возможностями обладает команда FC? Ну, например поддержкой подстановочных знаков. Если вам нужно сравнить некий файл etalon.exe с другими исполняемыми файлами в текущем каталоге, используйте команду следующего формата:
fc *.exe etalon.exe
Также с помощью подстановочных знаков можно производить пакетное сравнение файлов, расположенных в разных каталогах или разделах жёсткого диска. А что будет, если сравниваемые файлы окажутся полностью идентичными? Утилита выведет лаконичное сообщение — FC:различия не найдены.
Как сравнить два бинарных файла
Для сравнения бинарных файлов можно воспользоваться командами:
diff -u <(od -A x -t x1 ref.bmp) <(od -A x -t x1 orig.bmp)
diff <(xxd orig.bmp) <(xxd ref.bmp)
Что делают эти команды? Сначала выводится содержимое файлов в HEX-виде с помощью команд od или xxd . А потом через diff сравнивается уже это HEX-представление.
Традиционно, если различий нет, команда diff закончится молча, без вывода каких-либо сообщений.
Однако надо понимать, что большие файлы (около 2 GB) таким способом сравнить невозможно, как минимум на 32-х битных системах. Будет появляться ошибка:
diff: память исчерпана
Причем, судя по htop, память не расходуется. Это какие-то внутренние ограничения толи diff, толи od, толи xxd, толи механизма потока. Как обойти эту проблему — не знаю.
Вместо команды diff можно воспользоваться командой cmp :
cmp -b -l file1 file2
683263 161 q 150 h
683264 222 M-^R 377 M-^?
683265 212 M-^J 354 M-l
Программа cmp способна нормально работать с большими файлами. Она показывает адрес байта и два значения — в первом и втором файле.
How do I compare binary files in Linux?
Is there a way to do this in Linux? I know about cmp -l but it uses a decimal system for offsets and octal for bytes which I would like to avoid.
17 Answers 17
This will print the offset and bytes in hex:
Or do $1-1 to have the first printed offset start at 0.
Unfortunately, strtonum() is specific to GAWK, so for other versions of awk—e.g., mawk—you will need to use an octal-to-decimal conversion function. For example,
Broken out for readability:
quack pointed out:
diff + xxd
Try diff in the following combination of zsh/bash process substitution:
- -y shows you differences side-by-side (optional).
- xxd is CLI tool to create a hexdump output of the binary file.
- Add -W200 to diff for wider output (of 200 characters per line).
- For colors, use colordiff as shown below.
colordiff + xxd
If you’ve colordiff , it can colorize diff output, e.g.:
Otherwise install via: sudo apt-get install colordiff .

vimdiff + xxd
You can also use vimdiff , e.g.
- if files are too big, add limit (e.g. -l1000 ) for each xxd
There’s a tool called DHEX which may do the job, and there’s another tool called VBinDiff.
For a strictly command-line approach, try jojodiff.
Method that works for byte addition / deletion
Generate a test case with a single removal of byte 64:
If you also want to see the ASCII version of the character:
Tested on Ubuntu 16.04.
I prefer od over xxd because:
- it is POSIX, xxd is not (comes with Vim)
- has the -An to remove the address column without awk .
- -An removes the address column. This is important otherwise all lines would differ after a byte addition / removal.
- -w1 puts one byte per line, so that diff can consume it. It is crucial to have one byte per line, or else every line after a deletion would become out of phase and differ. Unfortunately, this is not POSIX, but present in GNU.
- -tx1 is the representation you want, change to any possible value, as long as you keep 1 byte per line.
- -v prevents asterisk repetition abbreviation * which might interfere with the diff
- paste -d » — — joins every two lines. We need it because the hex and ASCII go into separate adjacent lines. Taken from: https://stackoverflow.com/questions/8987257/concatenating-every-other-line-with-the-next
- we use parenthesis () to define bdiff instead of <> to limit the scope of the inner function f , see also: https://stackoverflow.com/questions/8426077/how-to-define-a-function-inside-another-function-in-bash
![]()
When using hexdumps and text diff to compare binary files, especially xxd , the additions and removals of bytes become shifts in addressing which might make it difficult to see. This method tells xxd to not output addresses, and to output only one byte per line, which in turn shows exactly which bytes were changed, added, or removed. You can find the addresses later by searching for the interesting sequences of bytes in a more «normal» hexdump (output of xxd first.bin ).
![]()
I’d recommend hexdump for dumping binary files to textual format and kdiff3 for diff viewing.
The firmware analysis tool binwalk also has this as a feature through its -W / —hexdump command line option which offers options such as to only show the differing bytes:
In OP’s example when doing binwalk -W file1.bin file2.bin :

Add | less -r for paging.
![]()
The hexdiff is a program designed to do exactly what you’re looking for.
It displays the hex (and 7-bit ASCII) of the two files one above the other, with any differences highlighted. Look at man hexdiff for the commands to move around in the file, and a simple q will quit.
It may not strictly answer the question, but I use this for diffing binaries:
It prints both files out as hex and ASCII values, one byte per line, and then uses Vim’s diff facility to render them visually.
Below is a Perl script, colorbindiff, which performs a binary diff, taking into account bytes changes but also byte additions/deletions (many of the solutions proposed here only handle byte changes), like in a text diff. It’s also available on GitHub.
It displays results side by side with colors, and this greatly facilitate analysis.
![]()
How to compare binary files, hex files, and Intel hex firmware files with meld
Mirror mirror on the wall, which is the most amazing solution of them all?
It’s this one: from @kenorb!—for sure! I upvoted it. Now, let me show you how amazing it looks and how easy it is to use with meld :

Quick summary
Get the latest version of my hex2xxdhex function in my eRCaGuy_dotfiles repo here: .bash_useful_functions. Copy and paste that function to the bottom of your
/.bashrc file. Then, re-source your
/.bashrc file with .
/.bashrc . Finally, use my hex2xxdhex function like this:
In the above comparison of the two *.xxd*.hex files, you’ll see all of the hex chars, followed by the binary/ASCII chars in a column on the right-hand-side, allowing you to more easily identify hex file differences between the two files.
The .xxd_short.hex files are simply the same as the .xxd.hex files, except with all lines containing only zeros removed. This way, if your hex file places portions of your firmware at drastically different address locations, all of the padded zeros between the two address locations are removed.
If your initial .hex file is 3.5 MB, your .bin file might be 45 MB, your .xxd.hex file might be 200 MB, and your .xxd_short.hex file (with all rows of pure zeros) might be 5 MB. meld can compare two 5 MB files just fine, but it struggles with 200 MB files. That’s why I generate the .xxd_short.hex version too.
Other options:
Details:
Compare binary files with meld
First, install it in Linux Ubuntu with sudo apt install meld . Then, use it to compare binary files like this:
The first command above gives you this view, highlighting the exact differences, on a line-by-line and character-by-character level, between the left and right files. Notice the highlighted slivers in the right scroll bar too, which indicate where lines differ in the entire file:

Navigation in Meld:
- You can find the next change with Alt + Down and the previous change with Alt + Up .
- Or, you can hover your cursor over the center space exactly between the left and right sides, and scroll up and down with the mouse wheel to jump just between the changes.
- Limitation: it will not search around line wraps. For that, try vbindiff instead.
Great tool! I am going to use this extensively now as I compare microcontroller .hex firmware files to identify minor differences between some builds, such as changed IP addresses, embedded filenames, or timestamps.
The ingeniousness of the command above is how it uses xxd first to convert a binary file to a hex + binary ASCII-text-side-bar view so that you can see human-readable text as well as the hex code.
Compare standard .hex files with meld
Perhaps you have previously converted binary files to .hex files, like this:
In that case, just use meld directly:
Compare Intel .hex microcontroller firmware files with meld
Intex .hex files don’t have the nice human-readable binary ASCII-text-side-bar on the right. So, first we must convert them to binary .bin files, using objcopy , as this answer shows, like this:
Do not forget the my_firmware1.bin part at the end or else you’ll get an unexpected behavior: my_firmware1.hex will be converted to binary in-place! Oh no! There goes your hex file!
Now, compare the binary files in meld , using xxd to convert them back to ASCII hex with the pretty human-readable side-bar:
Even better, do both steps above in one, like this "one-liner":
Keep in mind though you need to use your compiler’s version of the objcopy executable to do the above operations. So, for the Microchip MPLAB X XC32 compiler toolchain, for instance, use xc32-objcopy instead of objcopy :
Using only non-GUI CLI tools ( meld is a GUI).
If you really need to use non-GUI tools, such as through an ssh session, here are some more options. Alternatively, you could just scp the file back to your local machine over ssh, and then use meld as described above.
Pure CLI tools for binary comparison:
Use diff : refer back to @kenorb’s answer above]. Here are some of my own spins on those commands which I think are more useful:
Example run and output:
Here’s a screenshot so you can more easily see the colored changes:

Use vbindiff : I first learned about this tool here: How-To Geek: How to Compare Binary Files on Linux.
Here is how to install and use it:
Here’s what it looks like on the 2nd change shown above. As you can see, it has highlighted the exact character differences in red. It’s a pretty nice tool:

- See man vbindiff for details. It’s a short and easy manual.
- Press Space or Enter to go to the next difference. I hit Space twice to go to the 2nd difference in the screenshot above.
- Press Q or Esc to quit.
- You can scroll with the mouse scroll wheel, arrow keys, PageUp/Down keys, etc.
- Press T to toggle on scrolling only the top window.
- Press B to toggle on scrolling only the bottom window.
- Press F to find.
The navigation is really pretty limited. I don’t see a way to go back up and find a previous change. Just quit and start again.
How did I produce the binary files used in the examples above?
file2.c:
Now produce the executables, file1.bin and file2.bin , from those C files above: