9 votes

Comparaison des exécutables générés pour l'équivoque

J'ai besoin de comparer 2 exécutables et/ou objets partagés, compilés en utilisant le même compilateur/flags et vérifier qu'ils n'ont pas changé. Nous travaillons dans un environnement réglementé, il serait donc très utile à des fins de test d'isoler exactement les parties de l'exécutable qui ont changé.

L'utilisation de MD5Sums/Hashes ne fonctionne pas, car les en-têtes contiennent des informations sur le fichier.

Quelqu'un connaît-il un programme ou un moyen de vérifier que deux fichiers sont identiques du point de vue de l'exécution, même s'ils ont été créés à des moments différents ?

5voto

David Tonhofer Points 1816

Une question intéressante. J'ai un problème similaire sous linux. Les systèmes de détection d'intrusion comme OSSEC ou tripwire peuvent générer des faux positifs si le hashsum d'un exécutable change tout d'un coup. Cela peut n'être rien de pire que le programme "prelink" de Linux Parcheando le fichier exécutable pour des démarrages plus rapides.

Afin de comparer deux binaires (dans le format Format ELF ), on peut utiliser l'exécutable "readelf" et ensuite "diff" pour comparer les sorties. Je suis sûr qu'il existe des solutions plus raffinées, mais sans plus attendre, un comparateur du pauvre 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;
}

Maintenant vous pouvez exécuter par exemple, sur la machine 1 :

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

Et sur la machine 2 :

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

Après avoir copié, transféré par SFTP ou NSF (vous n'utilisez pas FTP, n'est-ce pas ?) les fichiers dans la même arborescence, comparez-les :

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

Dans mon cas, il y a des différences dans les sections ".gnu.conflict", ".gnu.liblist", ".got.plt" et ".dynbss", ce qui pourrait être correct pour une intervention "prelink", mais dans la section code, ".text", ce qui serait un mauvais signe.

1voto

Luciano Points 464

Pour poursuivre, voici ce que j'ai finalement trouvé :

Au lieu de comparer les exécutables finaux et les objets partagés, nous avons comparé les fichiers .o produits avant l'édition de liens. Nous avons supposé que le processus d'édition de liens était suffisamment reproductible pour que cela soit correct.

Cela fonctionne dans certains de nos cas, lorsque nous avons deux builds et que nous avons fait un petit changement qui ne devrait pas affecter le code final (Code pretty-printer) mais qui ne nous aide pas si nous n'avons pas la sortie intermédiaire du build.

0voto

hesham_EE Points 641

Vous pouvez comparer le contenu des sections initialisées RO et RW en générant un fichier binaire à partir du fichier ELF.

objcopy <elf_file> -O binary <binary_file>

Utilisez les fichiers binaires générés pour comparer s'ils sont identiques, à l'aide de la fonction diff par exemple.

A mon avis, c'est suffisant pour garantir que vous générez le même exécutable.

-1voto

richard Points 1651

Il y a quelques années, j'ai dû faire la même chose. Nous devions prouver que nous pouvions reconstruire l'exécutable à partir des sources en ne disposant que d'un numéro de révision, d'un référentiel de contrôle de révision, d'outils de construction et d'une configuration de construction. Note : Si tout de ces changements, vous verrez peut-être une différence.

Je me souviens qu'il y a des horodatages dans l'exécutable. Le truc est de réaliser que le fichier n'est pas juste un tas d'octets, qui ne peut pas être interprété. Le fichier a des sections, la plupart ne changeront pas, mais il y aura une section pour le temps de construction (ou quelque chose comme ça).

Je ne me souviens pas de tous les détails, mais les commandes dont vous aurez besoin sont { objcopy, objdump, nm }, je crois. objdump serait le premier à essayer.

J'espère que cela vous aidera.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X