Pregunta ¿Cómo comparo archivos binarios en Linux?


Necesito comparar dos archivos binarios y obtener el resultado en forma

<fileoffset-hex> <archivo1-byte-hex> <archivo2-byte-hex>

para cada byte diferente. Así que si file1.bin es

  00 90 00 11

en forma binaria y file2.bin es

  00 91 00 10

Quiero obtener algo como

  00000001 90 91
  00000003 11 10

¿Cuál es la forma más fácil de lograr el objetivo? Herramienta estándar? ¿Alguna herramienta de terceros?

(Nota: cmp -l debe eliminarse con fuego, usa un sistema decimal para las compensaciones y octal para los bytes).


253


origen


básicamente buscas "diferencias binarias". me puedo imaginar alguna línea de comandos feo feo con una sola línea con od... - quack quixote
@quack quixote: ¿Qué hay de feo en un trazador de líneas? ;) - Bobby
xdelta.org funciona bastante bien. Tal vez valdría la pena echarle un vistazo. - thatjuan


Respuestas:


Esto imprimirá el desplazamiento y los bytes en hexadecimal:

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

O hacer $1-1 tener el primer desplazamiento impreso comienza en 0.

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

Desafortunadamente, strtonum() es específico para GAWK, por lo que para otras versiones de awk-e.g., mawk, necesitará usar una función de conversión de octal a decimal. Por ejemplo,

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

Descompuesto para la legibilidad:

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



Desafortunadamente, esto me da awk: line 2: function strtonum never defined errores en Ubuntu 12.04. ¿Implementación específica de AWK tal vez? - gertvdijk
@gertvdijk: strtonum es específico para GAWK. Creo que Ubuntu utilizó previamente GAWK como el predeterminado, pero cambió en algún momento a mawk. En cualquier caso, GAWK se puede instalar y configurar de manera predeterminada (ver también man update-alternatives) Vea mi respuesta actualizada para una solución que no requiere strtonum. - Dennis Williamson
Agregué imprimiendo el carácter original y lo puse en el menú mc, tuve que duplicar el% de signos: 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 ~ curandero señaló:

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

Y entonces

 % diff b1.hex b2.hex

o

 % vimdiff b1.hex b2.hex

137



En Bash: diff <(xxd b1) <(xxd b2) pero el formato de salida de esto (o el tuyo) no está cerca de lo que pidió el OP. - Dennis Williamson
con vimdiff, coloreará los bytes en las líneas donde difieren los dos "archivos" - akira
Esto funcionó muy bien para mí (con opendiff en OS X en lugar de vimdiff) - la vista por defecto xxd proporciona mantiene el motor diff en pista comparando byte a byte. Con hexágono liso (crudo) simplemente en forma de columna con fold, diff Intentaría doblar / agrupar cosas aleatorias en los archivos que estaba comparando. - natevw
Este comando no funciona bien para la eliminación de adición de bytes, ya que cada línea que sigue estará desalineada y se verá modificada por diff. La solución es poner 1 byte por línea y eliminar la columna de dirección según lo propuesto por John Lawrence Aspden y yo. - Ciro Santilli 新疆改造中心 六四事件 法轮功
Su respuesta es perfecta, está bien para archivos pequeños, pero no tan bien para grandes. - peterh


Tratar diff en la siguiente combinación de sustitución de proceso zsh / bash y colordiff en CLI:

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

Dónde:

  • -y le muestra las diferencias lado a lado (opcional)
  • xxd es la herramienta CLI para crear una salida de hexdump del archivo binario
  • colordiff se coloreará diff salida (instalar a través de: sudo apt-get install colordiff)
  • añadir -W200 a diff para una producción más amplia

Sugerencias:

  • si los archivos son grandes, agregue el límite (p. -l1000) para cada xxd

Muestra de salida:

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


57



El comando se puede simplificar como colordiff -y <(xxd foo1.bin) <(xxd foo2.bin). - golem
Si no tienes colordiff, esto hará lo mismo sin colores: diff -y <(xxd foo1.bin) <(xxd foo2.bin) - Rock Lee
Si solo desea saber si ambos archivos son realmente iguales, puede usar -q o --brief cambiar, que solo mostrará la salida cuando los archivos difieren. - Stefan van den Akker
crear una función xxddiff para esto con: xxddiff() ( f() ( xxd "$1" ; ); diff -y <(f "$1") <(f "$2") | colordiff; ) - rubo77
¡estupendo! todavía, diff -u <(xxd tinga.tgz) <(xxd dec.out.tinga.tgz) | vim -  hará un buen trabajo enoug - ribamar


Hay una herramienta llamada DHEX que puede hacer el trabajo, y hay otra herramienta llamada VBinDiff.

Para un enfoque estrictamente de línea de comandos, intente JDIFF.


48



DHEX es asombroso es que comparar binarios es lo que quieres hacer. Aliméntalo con dos archivos y te llevará directamente a una vista comparativa, resaltando las diferencias, con la facilidad de pasar a la siguiente diferencia. También es capaz de funcionar con terminales grandes, lo cual es muy útil en monitores de pantalla panorámica. - Marcin
Prefiero VBinDiff. DHEX está utilizando la CPU incluso cuando está inactivo, creo que está redibujando todo el tiempo o algo así. Sin embargo, VBinDiff no funciona con terminales anchos. Pero las direcciones se vuelven extrañas con terminales anchos de todos modos, ya que tiene más de 16 bytes por fila. - Janus Troelsen
vbindiff nos permite editar el archivo, ¡gracias! - Aquarius Power
Los archivos comprimidos de @DanielBeauyat serán completamente diferentes después de encontrar el primer byte diferente. La salida no es útil. - Mark Ransom
@ 1111161171159459134 jdiff es parte de un "paquete" de programas para sincronizar y parchar las diferencias encontradas por jdiff. Pero, como dijo Mark Ransom, eso generalmente no sería sensato en los archivos comprimidos; la excepción son los formatos comprimidos "sincronizables" (como el producido por gzip --rsyncable), en los que pequeñas diferencias en los archivos descomprimidos deberían tener un efecto limitado en el archivo comprimido. - hmijail


Método que funciona para la adición / eliminación de bytes

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

Genere un caso de prueba con una sola eliminación del 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

Salida:

64d63
<  40

Si también quieres ver la versión ASCII del personaje:

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

bdiff file1 file2

Salida:

64d63
<   40   @

Probado en Ubuntu 16.04.

yo prefiero od encima xxd porque:

  • eso es POSIX, xxd no es (viene con Vim)
  • tiene el -An para eliminar la columna de dirección sin awk.

Explicación del comando:

  • -An elimina la columna de dirección. Esto es importante, de lo contrario, todas las líneas diferirían después de la adición / eliminación de un byte.
  • -w1 pone un byte por línea, por lo que diff puede consumirlo. Es crucial tener un byte por línea, o de lo contrario cada línea después de una eliminación se desfasará y se diferenciará. Desafortunadamente, esto no es POSIX, pero está presente en GNU.
  • -tx1 es la representación que desea, cambie a cualquier valor posible, siempre que conserve 1 byte por línea.
  • -v evita la abreviatura de repetición de asterisco * que podría interferir con el diff
  • paste -d '' - - se une a cada dos líneas. Lo necesitamos porque el hexágono y ASCII entran en líneas adyacentes separadas. Tomado de: https://stackoverflow.com/questions/8987257/concatenating-every-other-line-with-the-next
  • usamos paréntesis () definir bdiff en lugar de {} para limitar el alcance de la función interna f, ver también: https://stackoverflow.com/questions/8426077/how-to-define-a-function-inside-another-function-in-bash

Ver también:


25





Respuesta corta

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

Al usar hexadecimales y diff de texto para comparar archivos binarios, especialmente xxd, las adiciones y eliminaciones de bytes se convierten en cambios en el direccionamiento que pueden dificultar ver. Este método le dice a xxd que no genere direcciones, y que genere solo un byte por línea, que a su vez muestra exactamente qué bytes se cambiaron, agregaron o eliminaron. Puede encontrar las direcciones más tarde buscando las interesantes secuencias de bytes en un hexdump más "normal" (salida de xxd first.bin)


12



(Por supuesto, uno puede usar diff en lugar de vimdiff.) - VasyaNovikov


Recomiendo hexdump para descargar archivos binarios a formato de texto y kdiff3 para ver diferencias.

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

10



Incluso aquí en bash kdiff3 <(hexdump myfile1.bin) <(hexdump myfile2.bin) sin necesidad de crear archivos myfile1.hex y myfile2.hex. - Hastur


los hexdiff es un programa diseñado para hacer exactamente lo que estás buscando.

Uso:

hexdiff file1 file2

Muestra el hex (y el ASCII de 7 bits) de los dos archivos, uno encima del otro, con las diferencias resaltadas. Mirar man hexdiff para que los comandos se muevan en el archivo, y un simple q se dará por vencido


4



Pero hace un trabajo bastante malo cuando se trata de la parte de comparación. Si inserta algunos bytes en un archivo, marcará todos los bytes luego como cambios - Murmel
y hexdiff no está disponible a través de apt-get en Ubuntu 16.4 - rubo77


Puede que no responda estrictamente a la pregunta, pero la uso para diferir binarios:

gvim -d <(xxd -c 1 ~/file1.bin | awk '{print $2, $3}') <(xxd -c 1 ~/file2.bin | awk '{print $2, $3}')

Imprime ambos archivos como hexadecimales y ASCII valores, un byte por línea, y luego utiliza la facilidad de diff de Vim para representarlos visualmente.


3