Как сравнить двоичные файлы в Linux?

304

Мне нужно сравнить два двоичных файла и получить вывод в виде:

<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но он использует десятичную систему для смещений и восьмеричную для байтов, которых я хотел бы избежать.

bertieb
источник
9
вы в основном ищете "бинарный дифференциал". я могу вообразить какой-то по-настоящему уродливый однострочник командной строки с od...
Quack Quixote
2
@ Quack Quixote: Что страшного в однострочнике? ;)
Бобби
xdelta.org работает довольно хорошо. Возможно, стоило бы взглянуть на это.
июня
Поскольку вы не можете ответить на этот вопрос (поскольку вы не пользователь), я голосую, чтобы закрыть. Бинарный diff, как явно запрашивается здесь, совсем не полезен, и я склонен думать, что вы хотите что-то полезное, если вы вставляете один байт в начало файла, все ли байты должны быть помечены как разные? Не зная этого, это просто слишком расплывчато.
Эван Кэрролл
2
@EvanCarroll Если вы думаете, что вопрос не по теме, почему вы отвечаете на него?
DavidPostill

Ответы:

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.
Деннис Уильямсон
Почему бы просто не сравнить сумму sha256 обоих файлов?
Родриго
1
@Rodrigo: Этот и другие методы покажут, отличаются ли файлы. Мой ответ соответствует требованию ОП, чтобы показать, в чем заключаются различия.
Деннис Уильямсон
Конечно! Извините, я так волновалась о своей проблеме, что едва читала ОП. Спасибо.
Родриго
166

Как сказал Кряк :

 % 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
Ой, почему я не подумал об этом? И я уверен, что я использовал эту технику и в прошлом.
Njd
1
Это прекрасно сработало для меня (с opendiffOS X вместо vimdiff) - представление по умолчанию xxdобеспечивает, что механизм сравнения отслеживает сравнение байтов за байтом. При использовании простого (необработанного) шестнадцатеричного кода, в который просто помещается столбец fold, я diffбы попытался сложить / сгруппировать случайные вещи в файлах, которые я сравнивал.
natevw
1
Эта команда плохо работает для удаления байтов, так как каждая следующая строка будет выровнена и будет видна как измененная diff. Решение состоит в том, чтобы поместить 1 байт в строку и удалить столбец адреса, как предложено Джоном Лоуренсом Аспденом и мной .
Чиро Сантилли 新疆 改造 中心 法轮功 六四 事件
98

diff + xxd

Попробуйте diffиспользовать следующую комбинацию подстановки zsh / bash:

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

Где:

  • -y показывает различия между собой (необязательно).
  • xxd инструмент CLI для создания шестнадцатеричного вывода двоичного файла
  • Добавить -W200к diffдля более широкого выхода (из 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) |  colordiff

vimdiff + xxd

Вы также можете использовать vimdiff, например,

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

подсказки:

  • если файлы слишком большие, добавьте ограничение (например -l1000) для каждогоxxd
kenorb
источник
11
Команду можно упростить как colordiff -y <(xxd foo1.bin) <(xxd foo2.bin).
Голем
3
Если у вас нет colordiff, это сделает то же самое без цветов:diff -y <(xxd foo1.bin) <(xxd foo2.bin)
Рок Ли
5
Если вы просто хотите узнать, являются ли оба файла на самом деле одинаковыми, вы можете использовать переключатель -qили --brief, который будет отображать вывод только тогда, когда файлы различаются.
Стефан ван ден Аккер
1
создать xxddiffдля этого функцию с:xxddiff() ( f() ( xxd "$1" ; ); diff -y <(f "$1") <(f "$2") | colordiff; )
rubo77
2
здорово! diff -u <(xxd tinga.tgz) <(xxd dec.out.tinga.tgz) | vim - Тем не менее, сделаю работу хорошо enoug
Рибамар
57

Есть инструмент под названием DHEX, который может сделать эту работу, и есть другой инструмент, который называется VBinDiff .

Для строго командной строки, попробуйте jojodiff .

NJD
источник
8
DHEX потрясающе сравнивает двоичные файлы - это то, что вы хотите сделать. Подайте в него два файла, и вы сразу перейдете к сравнительному виду, выделив различия, и легко сможете перейти к следующему различию. Также он может работать с большими терминалами, что очень полезно на широкоэкранных мониторах.
Марчин
7
Я предпочитаю VBinDiff. DHEX использует процессор даже на холостом ходу, я думаю, что он постоянно перерисовывается или что-то в этом роде. VBinDiff не работает с широкими терминалами. Но адреса в любом случае становятся странными с широкими терминалами, поскольку у вас больше 16 байтов на строку.
Янус Троелсен
1
vbindiff позволяет нам на самом деле редактировать файл, спасибо!
Водолей Power
2
Сжатые файлы @DanielBeauyat будут совершенно другими после того, как вы столкнетесь с первым другим байтом. Вывод вряд ли будет полезным.
Марк Рэнсом
2
@ 1111161171159459134 jdiff является частью "набора" программ для синхронизации и исправления различий, обнаруженных jdiff. Но, как сказал Марк Рэнсом, на сжатых файлах это было бы неразумно; исключение составляют «синхронизируемые» сжатые форматы (например, созданные gzip --rsyncable), в которых небольшие различия в несжатых файлах должны оказывать ограниченное влияние на сжатый файл.
hmijail
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.

Я предпочитаю odболее , xxdпотому что:

  • это POSIX , xxdнет (поставляется с Vim)
  • имеет, -Anчтобы удалить столбец адреса без awk.

Объяснение команды:

  • -Anудаляет адресную колонку Это важно, иначе все строки будут отличаться после добавления / удаления байта.
  • -w1помещает один байт в строку, чтобы diff мог его использовать. Крайне важно иметь один байт на строку, иначе каждая строка после удаления окажется не в фазе и будет отличаться. К сожалению, это не POSIX, но присутствует в GNU.
  • -tx1 это представление, которое вы хотите, замените любое возможное значение, пока вы сохраняете 1 байт на строку.
  • -vпредотвращает повторение звездочки, *которое может помешать
  • paste -d '' - -соединяет каждые две строки. Нам это нужно, потому что гекс и ASCII идут в отдельные соседние строки. Взято из: https://stackoverflow.com/questions/8987257/concatenating-every-other-line-with-the-next
  • мы используем скобки ()для определения, bdiffа не {}для ограничения объема внутренней функции f, см. также: https://stackoverflow.com/questions/8426077/how-to-define-a-function-inside-another-function-in-bash

Смотрите также:

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
источник
13

Краткий ответ

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

При использовании hexdumps и text diff для сравнения двоичных файлов, особенно xxd, добавления и удаления байтов становятся изменениями в адресации, что может затруднить просмотр. Этот метод говорит xxd не выводить адреса и выводить только один байт на строку, что, в свою очередь, показывает, какие именно байты были изменены, добавлены или удалены. Вы можете найти адреса позже, выполнив поиск интересных последовательностей байтов в более "нормальном" hexdump (вывод xxd first.bin).

Евгений
источник
(Конечно, можно использовать diffвместо vimdiff.)
ВасяНовиков
11

Я бы порекомендовал hexdump для выгрузки двоичных файлов в текстовый формат и kdiff3 для просмотра различий.

hexdump myfile1.bin > myfile1.hex
hexdump myfile2.bin > myfile2.hex
kdiff3 myfile1.hex myfile2.hex
Bugok
источник
2
Даже здесь, в Bash kdiff3 <(hexdump myfile1.bin) <(hexdump myfile2.bin)без необходимости создавать файлы myfile1.hexи myfile2.hex.
Хастур
5

Это hexdiffпрограмма, предназначенная для того, чтобы делать именно то, что вы ищете.

Использование:

hexdiff file1 file2

Он отображает шестнадцатеричный (и 7-битный ASCII) двух файлов один над другим с выделением любых различий. Посмотрите на man hexdiffкоманды для перемещения в файле, и простое qзакроется.

Мик
источник
4
Но это делает довольно плохую работу, когда дело касается сравнения. Если вы вставите несколько байтов в файл, он
пометит
и hexdiff недоступен через apt-get в Ubuntu 16.4
rubo77
1
@ Мурмель, пока я согласен, не об этом ли здесь спрашивают?
Эван Кэрролл
@EvanCarroll true, и поэтому я оставил комментарий (только) и не понизил голос
Murmel
Я также не голосовал против Мика, но я согласен с вами и ответил здесь 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 для визуальной визуализации.

Джон Лоуренс Аспден
источник
0

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

DHEX - это не просто еще один шестнадцатеричный редактор: он включает режим diff, который можно использовать для простого и удобного сравнения двух двоичных файлов. Поскольку он основан на ncurses и является темным, он может работать в любом количестве систем и сценариев. Благодаря использованию журналов поиска можно легко отслеживать изменения в разных итерациях файлов.

Винсент Вега
источник
Добро пожаловать в SuperUser! Хотя это программное обеспечение выглядит так, как будто оно может решить проблему ОП, в сети Stack Exchange решительно осуждается чистая реклама. Если вы связаны с редактором этого программного обеспечения, пожалуйста, сообщите об этом факте. И попробуйте переписать свой пост, чтобы он не выглядел как рекламный ролик. Спасибо.
Натан. Элиша Ширайни
Я никак не связан с dhex. Я скопировал описание автора в пост, потому что есть минимальный предел длины поста
Винсент Вега
Уже упоминалось по адресу: superuser.com/a/125390/128124
Сиро Сантилли,
0

Вы можете использовать инструмент gvimdiff , который входит в пакет vim-gui-common

sudo apt-get update

sudo apt-get установить vim-gui-common

Затем вы можете сравнить 2 шестнадцатеричных файла, используя следующие команды:

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

Это все. Надеюсь, что помощь!

craken
источник
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

PHK
источник
-1

https://security.googleblog.com/2016/03/bindiff-now-available-for-free.html

BinDiff - это отличный инструмент для сравнения бинарных файлов, который был недавно открыт.

Евгений
источник
3
Можно ли его использовать для произвольных двоичных файлов? Похоже, что эта страница полезна для сравнения исполняемых файлов, которые были разобраны с помощью Hex-Rays IDA Pro.
Эсвальд
-2

Продуктом с открытым исходным кодом для Linux (и всего остального) является Radare, который radiff2специально предназначен для этой цели. Я проголосовал за это, потому что у меня и у других один и тот же вопрос в вопросе, который вы задаете

за каждый другой байт

Это безумие, хотя. Потому что, как и просили, если вы вставите один байт в первый байт в файле, вы обнаружите, что каждый последующий байт отличается, и поэтому diff будет повторять весь файл для фактической разницы в один байт.

Чуть более практичным является 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.

Если вы задаете такие вопросы, проверьте

Эван Кэрролл
источник