8

Necesito comparar 2 ejecutables y/u objetos compartidos, compilados usando el mismo compilador/banderas y verificando que no hayan cambiado. Trabajamos en un entorno regulado, por lo que sería realmente útil para propósitos de prueba aislar exactamente qué partes del ejecutable han cambiado.Comparación de ejecutables generados para la equivalencia

El uso de MD5Sums/Hashes no funciona debido a los encabezados que contienen información sobre el archivo.

¿Alguien sabe de un programa o forma de verificar que 2 archivos son ejecutados de manera ejecutable, incluso si se construyeron en un momento diferente?

+1

Probablemente depende de la plataforma .... – skaffman

+0

Ok, es Linux compilado con GCC. – Luciano

Respuesta

1

durante el seguimiento, esto es lo que ocurrió con el último:

En lugar de comparar los ejecutables finales & objetos compartidos, se comparó la salida de archivos .o antes de enlazar. Supusimos que el proceso de enlace era lo suficientemente reproducible como para que todo estuviera bien.

Funciona en algunos de nuestros casos, donde tenemos dos compilaciones donde hicimos un pequeño cambio que no debería afectar el código final (código pretty-printer) pero no nos ayuda si no tenemos la construcción de salida intermediaria.

4

Una pregunta interesante. Tengo un problema similar en Linux. Los sistemas de detección de intrusos como OSSEC o tripwire pueden generar falsos positivos si el hash de un ejecutable cambia repentinamente. Esto puede no ser nada peor que el programa de "prelink" de Linux parcheando el archivo ejecutable para arranques más rápidos.

Para comparar dos binarios (en el ELF format), se puede usar el ejecutable "readelf" y luego "diff" para comparar las salidas. Estoy seguro de que hay soluciones refinados, pero sin más preámbulos, comparador de un hombre pobre en Perl:

#!/usr/bin/perl -w 

$exe = $ARGV[0]; 

if (!$exe) { 
    die "Please give name of executable\n" 
} 
if (! -f $exe) { 
    die "Executable $exe not found or not a file\n"; 
} 
if (! (`file '$exe'` =~ /\bELF\b.*?\bexecutable\b/)) { 
    die "file command says '$exe' is not an ELF executable\n"; 
} 

# Identify sections in ELF 

@lines = pipeIt("readelf --wide --section-headers '$exe'"); 

@sections =(); 

for my $line (@lines) { 
    if ($line =~ /^\s*\[\s*(\d+)\s*\]\s+(\S+)/) { 
     my $secnum = $1; 
     my $secnam = $2; 
     print "Found section $1 named $2\n"; 
     push @sections, $secnam; 
    } 
} 

# Dump file header 

@lines = pipeIt("readelf --file-header --wide '$exe'"); 
print @lines; 

# Dump all interesting section headers 

@lines = pipeIt("readelf --all --wide '$exe'"); 
print @lines; 

# Dump individual sections as hexdump 

for my $section (@sections) { 
    @lines = pipeIt("readelf --hex-dump='$section' --wide '$exe'"); 
    print @lines; 
} 

sub pipeIt { 
    my($cmd) = @_; 
    my $fh; 
    open ($fh,"$cmd |") or die "Could not open pipe from command '$cmd': $!\n"; 
    my @lines = <$fh>; 
    close $fh or die "Could not close pipe to command '$cmd': $!\n"; 
    return @lines; 
} 

Ahora se puede ejecutar, por ejemplo, en la máquina 1:

./checkexe.pl /usr/bin/curl > curl_machine1 

Y en la máquina 2 :

./checkexe.pl /usr/bin/curl > curl_machine2 

Después de haber copypasted, SFTP-ed o NSF-ed (? no utiliza FTP, ¿verdad) los archivos en la misma FileTree, comparar los archivos:

diff --side-by-side --width=200 curl_machine1 curl_machine2 | less 

En mi caso, existen diferencias en la sección ".gnu.conflict", ".gnu.liblist", ".got.plt" y ".dynbss", que podría estar bien para una intervención de "prelink", pero en la sección de código, ".text", que sería un Bad Sign.

-1

Hace unos años tuve que hacer lo mismo. Tuvimos que demostrar que podíamos reconstruir el ejecutable desde el origen cuando solo se le proporcionaba un número de revisión, un repositorio de control de revisión, herramientas de compilación y configuración de compilación. Nota: Si cualquiera de los de estos cambios, es posible que vea una diferencia.

Recuerdo que hay algunas marcas de tiempo en el ejecutable. El truco consiste en darse cuenta de que el archivo no es solo un montón de bytes, que no se puede interpretar. El archivo tiene secciones, la mayoría no cambiará, pero habrá una sección para el momento de la construcción (o algo así). No recuerdo todos los detalles, pero los comandos que necesitará son {objcopy, objdump, nm}, creo que objdump sería el primero en intentarlo.

Espero que esto ayude.

Cuestiones relacionadas