ti-enxame.com

Como usar o "cmp" para comparar dois binários e encontrar todos os desvios de bytes em que eles diferem?

Gostaria muito de ajudar com um loop de script do Bash que mostrará todas as diferenças entre dois arquivos binários, usando apenas

cmp file1 file2 

Ele mostra apenas a primeira alteração que eu gostaria de usar o cmp, porque fornece um deslocamento e um número de linha de onde cada alteração está, mas se você acha que há um comando melhor, estou aberto a isso :) obrigado

30
lewis denny

Eu acho que cmp -l file1 file2 pode fazer o que você quiser. Na página de manual:

-l  --verbose
      Output byte numbers and values of all differing bytes.

A saída é uma tabela do deslocamento, o valor do byte no arquivo1 e o valor no arquivo2 para todos os bytes diferentes. Se parece com isso:

4531  66  63
4532  63  65
4533  64  67
4580  72  40
4581  40  55
[...]

Portanto, a primeira diferença está no deslocamento 4531, onde o valor do byte decimal do arquivo1 é 66 e o ​​arquivo2 é 63.

33
rwos

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

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

Resultado:

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

Resultado:

64d63
<   40   @

Testado no Ubuntu 16.04.

Eu prefiro od sobre xxd porque:

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

Explicação do comando:

  • -An remove a coluna de endereço. Isso é importante, caso contrário, todas as linhas diferirão após a adição/remoção de bytes.
  • -w1 coloca um byte por linha, para que o diff possa consumi-lo. É crucial ter um byte por linha, ou então todas as linhas após uma exclusão ficarão fora de fase e diferirão. Infelizmente, isso não é POSIX, mas está presente no GNU.
  • -tx1 é a representação que você deseja, altere para qualquer valor possível, desde que você mantenha 1 byte por linha.
  • -v evita abreviação de repetição de asterisco * que podem interferir na diferença
  • paste -d '' - - junta-se a cada duas linhas. Precisamos disso porque o hex e ASCII entram em linhas adjacentes separadas. Retirado de: Concatenando todas as outras linhas com a próxima
  • usamos parênteses () para definir bdiff em vez de {} para limitar o escopo da função interna f, consulte também: Como definir uma função dentro de outra função no bash

Veja também:

A solução mais eficiente que encontrei é converter arquivos binários em alguma forma de texto usando od.

Então qualquer sabor de diff funciona bem.

2
mouviciel