Questão Como faço para comparar arquivos binários no Linux?


Eu preciso comparar dois arquivos binários e obter a saída no formulário

<fileoffset-hex> <arquivo1-byte-hex> <arquivo2-byte-hex>

para cada byte diferente. Então se file1.bin é

  00 90 00 11

em forma binária e file2.bin é

  00 91 00 10

Eu quero algo como

  00000001 90 91
  00000003 11 10

Qual é a maneira mais fácil de atingir o objetivo? Ferramenta padrão? Alguma ferramenta de terceiros?

(Nota: cmp -l deve ser morto com fogo, ele usa um sistema decimal para deslocamentos e octal para bytes.)


253


origem


você está basicamente procurando por "diff binário". Eu posso imaginar um one-liner linha de comando feio com reeeally od... - quack quixote
@quack quixote: O que é feio em um one-liner? ;) - Bobby
O xdelta.org funciona muito bem. Talvez valesse a pena dar uma olhada nisso. - thatjuan


Respostas:


Isto irá imprimir o deslocamento e os bytes em hexadecimal:

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

Ou fazer $1-1 para que o primeiro deslocamento impresso comece em 0.

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

Infelizmente, strtonum() é específico para o GAWK, portanto, para outras versões do awk - por exemplo, mawk - você precisará usar uma função de conversão de octal para decimal. Por exemplo,

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

Quebrado por legibilidade:

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

143



Infelizmente, isso me dá awk: line 2: function strtonum never defined erros no Ubuntu 12.04. Implementação específica do AWK, talvez? - gertvdijk
@gertvdijk: strtonum é específico para o GAWK. Eu acredito que o Ubuntu usou anteriormente o GAWK como padrão, mas mudou em algum momento para mawk. Em qualquer caso, o GAWK pode ser instalado e definido como padrão (consulte também man update-alternatives). Veja minha resposta atualizada para uma solução que não exige strtonum. - Dennis Williamson
Acrescentei imprimindo o caractere original e coloquei no mc menu, tive que dobrar os% sinais: cmp -l %d/%f %D/%f | gawk '{printf "%%08X %%02X %%02X %%c %%c\n", $1-1, strtonum(0$2), strtonum(0$3), strtonum(0$2), strtonum(0$3)}' - 18446744073709551615


Como ~ quack apontou:

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

E depois

 % diff b1.hex b2.hex

ou

 % vimdiff b1.hex b2.hex

137



No Bash: diff <(xxd b1) <(xxd b2) mas o formato de saída disso (ou o seu) está longe do que o OP pediu. - Dennis Williamson
com o vimdiff, ele irá colorir os bytes nas linhas onde os dois 'arquivos' diferem - akira
Isso funcionou muito bem para mim (com opendiff no OS X em vez de vimdiff) - a visualização padrão xxd fornece mantém o mecanismo de comparação no caminho comparando byte por byte. Com o hex simples (cru), basta ajustar a coluna fold, diff tentaria dobrar / agrupar coisas aleatórias nos arquivos que eu estava comparando. - natevw
Este comando não funciona bem para a remoção de adição de bytes, pois todas as linhas a seguir serão desalinhadas e vistas como modificadas por diff. A solução é colocar 1 byte por linha e remover a coluna de endereço conforme proposta John Lawrence Aspden e mim. - Ciro Santilli 新疆改造中心 六四事件 法轮功
Sua resposta é perfeita para arquivos pequenos, mas não tão boa para os grandes. - peterh


Experimentar diff na seguinte combinação de substituição de processo zsh / bash e colordiff no CLI:

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

Onde:

  • -y mostra as diferenças lado-a-lado (opcional)
  • xxd é a ferramenta CLI para criar uma saída hexdump do arquivo binário
  • colordiff vai colorir diff saída (instalar via: sudo apt-get install colordiff)
  • adicionar -W200 para diff para uma produção mais ampla

Dicas:

  • Se os arquivos forem grandes, adicione limite (por exemplo, -l1000) para cada xxd

Exemplo de saída:

binary file output in terminal - diff -y <(xxd foo1.bin) <(xxd foo2.bin) | colordiff


57



Comando pode ser simplificado como colordiff -y <(xxd foo1.bin) <(xxd foo2.bin). - golem
Se você não tiver colordiff, isso fará a mesma coisa sem cores: diff -y <(xxd foo1.bin) <(xxd foo2.bin) - Rock Lee
Se você quer apenas saber se ambos os arquivos são realmente os mesmos, você pode usar o -q ou --brief switch, que mostrará apenas a saída quando os arquivos forem diferentes. - Stefan van den Akker
criar uma função xxddiff para isso com: xxddiff() ( f() ( xxd "$1" ; ); diff -y <(f "$1") <(f "$2") | colordiff; ) - rubo77
ótimo! ainda, diff -u <(xxd tinga.tgz) <(xxd dec.out.tinga.tgz) | vim -  vai fazer um bom trabalho enoug - ribamar


Existe uma ferramenta chamada DHEX que pode fazer o trabalho, e há outra ferramenta chamada VBinDiff.

Para uma abordagem estritamente de linha de comando, tente JDIFF.


48



DHEX é incrível é comparar binários é o que você quer fazer. Alimente-o com dois arquivos e leva-o diretamente a uma visão comparativa, destacando as diferenças, com a capacidade fácil de passar para a próxima diferença. Também é capaz de trabalhar com terminais grandes, o que é muito útil em monitores widescreen. - Marcin
Eu prefiro o VBinDiff. DHEX está usando CPU mesmo quando ocioso, eu acho que é redesenhar o tempo todo ou algo assim. O VBinDiff não funciona com terminais largos. Mas os endereços se tornam estranhos com terminais largos de qualquer maneira, desde que você tenha mais de 16 bytes por linha. - Janus Troelsen
vbindiff nos permite realmente editar o arquivo, thx! - Aquarius Power
Os arquivos compactados do @DanielBeauyat serão completamente diferentes depois que você encontrar o primeiro byte diferente. A saída provavelmente não será útil. - Mark Ransom
@ 1111161171159459134 jdiff é parte de um "conjunto" de programas para sincronizar e corrigir as diferenças encontradas pelo jdiff. Mas, como Mark Ransom disse, isso geralmente não seria sensato em arquivos compactados; a exceção são formatos compactados "sincronizáveis" (como os produzidos pelo gzip --rsyncable), nos quais pequenas diferenças nos arquivos descompactados devem ter um efeito limitado no arquivo compactado. - hmijail


Método que funciona para adição / exclusão de byte

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

Gere um caso de teste com uma única remoção do 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

Saída:

64d63
<  40

Se você também quiser ver a versão ASCII do personagem:

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

bdiff file1 file2

Saída:

64d63
<   40   @

Testado no Ubuntu 16.04.

eu prefiro od sobre xxd Porque:

  • isto é POSIX, xxd não é (vem com o Vim)
  • tem o -An para remover a coluna de endereço sem awk.

Explicação de comando:

  • -An remove a coluna de endereço. Isso é importante, caso contrário todas as linhas seriam diferentes após uma adição / remoção de byte.
  • -w1 coloca um byte por linha, para que diff possa consumi-lo. É crucial ter um byte por linha, ou então cada linha depois de uma exclusão se tornaria desfasada e diferente. Infelizmente, isso não é POSIX, mas presente no GNU.
  • -tx1 é a representação que você quer, mude para qualquer valor possível, contanto que você mantenha 1 byte por linha.
  • -v impede a abreviatura de repetição de asterisco * o que pode interferir no diff
  • paste -d '' - - junta-se a cada duas linhas. Precisamos disso porque o hex e o ASCII entram em linhas adjacentes separadas. Tirado de: https://stackoverflow.com/questions/8987257/concatenating-every-other-line-with-the-next
  • nós usamos parênteses () definir bdiff ao invés de {} para limitar o escopo da função interna f, Veja também: https://stackoverflow.com/questions/8426077/how-to-define-a-function-inside-other-function-in-bash

Veja também:


25





Resposta curta

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

Ao usar hexdumps e diff de texto para comparar arquivos binários, especialmente xxd, as adições e remoções de bytes tornam-se mudanças no endereçamento que podem dificultar a visualização. Esse método informa ao xxd para não gerar endereços e gerar apenas um byte por linha, o que, por sua vez, mostra exatamente quais bytes foram alterados, adicionados ou removidos. Você pode encontrar os endereços mais tarde procurando as sequências interessantes de bytes em um hexdump mais "normal" (saída de xxd first.bin).


12



(Claro, pode-se usar diff ao invés de vimdiff.) - VasyaNovikov


Eu recomendaria o hexdump para despejar arquivos binários em formato textual e o kdiff3 para visualização em modo diff.

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

10



Mesmo aqui no bash kdiff3 <(hexdump myfile1.bin) <(hexdump myfile2.bin) sem necessidade de criar arquivos myfile1.hex e myfile2.hex. - Hastur