27 votes

Déterminer si les assemblages .NET ont été construits à partir de la même source.

Quelqu'un connaît-il un moyen de comparer deux assemblages .NET pour déterminer s'ils ont été construits à partir des "mêmes" fichiers sources ?

Je sais qu'il existe des utilitaires de différenciation, comme le plugin pour Reflector, mais je ne suis pas intéressé par l'affichage des différences dans une interface graphique, je veux juste un moyen automatisé de comparer une collection de binaires pour voir s'ils ont été construits à partir des mêmes fichiers sources (ou de fichiers équivalents). Je comprends que plusieurs fichiers sources différents peuvent produire la même IL, et je réalise que le processus ne serait sensible qu'aux différences dans l'IL, pas dans la source originale.

Le principal obstacle à la simple comparaison des flux d'octets pour les deux assemblages est que .NET inclut un champ appelé "MVID" (Module Version Identifier) dans l'assemblage. Ce champ semble avoir une valeur différente pour chaque compilation, donc si vous construisez le même code deux fois, l'assemblage sera différent.

Une question connexe : quelqu'un sait-il comment forcer le MVID à être le même pour chaque compilation ? Cela nous éviterait d'avoir à mettre en place un processus de comparaison qui soit insensible aux différences de valeur du MVID. Un MVID cohérent serait préférable, car cela signifie que des sommes de contrôle standard pourraient être utilisées.

En effet, une société tierce est chargée d'examiner et de signer nos communiqués de manière indépendante, avant que nous soyons autorisés à les diffuser à la production. Cela inclut l'examen du code source. Elle veut confirmer de manière indépendante que le code source que nous lui donnons correspond aux binaires que nous avons construits et testés précédemment et que nous prévoyons actuellement de déployer. Nous recherchons un processus qui leur permette de construire indépendamment le système à partir du code source que nous leur fournissons, et de comparer les sommes de contrôle aux sommes de contrôle des binaires que nous avons testés.

BTW. Veuillez noter que nous utilisons l'intégration continue, les constructions automatisées, le contrôle des sources, etc. Le problème n'est pas lié à un manque de contrôle interne sur les fichiers sources utilisés dans une construction donnée. Le problème est qu'un tiers est chargé de vérifier que la source que nous lui donnons produit les mêmes binaires que ceux que nous avons testés et que nous prévoyons de mettre en production. Elle ne devrait pas faire confiance à nos systèmes ou contrôles internes, y compris le serveur de compilation ou le système de contrôle du code source. Tout ce qui les intéresse, c'est d'obtenir la source associée à la construction, d'effectuer la construction eux-mêmes et de vérifier que les résultats correspondent à ce que nous disons que nous déployons.

La vitesse d'exécution de la solution de comparaison n'est pas particulièrement importante.

merci

10voto

Jerry Currry Points 81

Il n'est pas trop difficile d'utiliser des outils en ligne de commande pour filtrer le MVID et les horodateurs à partir d'une représentation textuelle de l'IL. Supposons que file1.exe et file2.exe soient construits à partir des mêmes sources :

c : \temp > ildasm /all /text file1.exe | find /v "Time-date stamp :" | find /v "MVID" > file1.txt

c : \temp > ildasm /all /text file2.exe | find /v "Time-date stamp :" | find /v "MVID" > file2.txt

c : \temp > fc fichier1.txt fichier2.txt

Comparaison des fichiers file1.txt et FILE2.TXT

FC : aucune différence rencontrée

8voto

R. Schreurs Points 952

J'ai utilisé la solution de Jerry Currry sur les assemblages .Net 4 et j'ai découvert qu'il y a maintenant un troisième élément qui varie sur chaque build : La somme de contrôle. N'est-il pas surprenant de trouver une somme de contrôle dans un assemblage ? Je pense que l'ajout de la somme de contrôle d'un fichier à l'intérieur de ce fichier va changer la somme de contrôle...

Quoi qu'il en soit, la commande modifiée est :

ildasm /all /text "assembly.dll"
| find /v "// Time-date stamp:"
| find /v "// MVID:"
| find /v "// Checksum:"
> assembly.dasm

Notez que j'ai également modifié un peu les chaînes de recherche en ajoutant les barres obliques, afin d'éviter les correspondances involontaires. Les lignes de cette commande doivent être exécutées sur la même ligne, séparées pour plus de lisibilité. Les noms de fichiers devront être entourés de guillemets doubles s'ils contiennent des espaces.

6voto

GregC Points 4679

En comparant les bibliothèques de classes avec ILDasm v4.0.319.1, il semble que la base d'images ne soit pas initialisée. Pour éviter les incompatibilités, utilisez une solution révisée :

ildasm /all /text assembly.dll
| find /v "// Time-date stamp:"
| find /v "// MVID:"
| find /v "// Checksum:"
| find /v "// Image base:"
> assembly.dasm

Le point d'entrée (base d'images) est en fait une information intéressante pour les assemblages exécutables, et devra être vérifié avec soin. L'injection d'une nouvelle base d'images est un moyen courant de faire faire à un programme quelque chose de complètement différent. Dans mon cas, j'essaie de vérifier la cohérence des constructions multithread, il est donc prudent de ne pas tenir compte du point d'entrée.

Une note sur la performance : J'ai pris une DLL de 8MB qui a été construite pour AnyCPU, et j'ai exécuté ILDasm. Le fichier résultant faisait 251 Mo et a pris plusieurs minutes pour être créé. Environ 32x la taille a été produite.

3voto

Diadistis Points 6892

Il existe plusieurs façons de le faire, en fonction de la quantité de travail que vous êtes prêt à faire et de l'importance des performances et/ou de la précision. L'une d'entre elles, comme l'a indiqué Eric J., consiste à comparer les assemblages en binaire, en excluant les parties qui changent à chaque compilation. Cette solution est facile et rapide mais peut donner beaucoup de faux négatifs. Une meilleure solution est d'aller plus loin en utilisant la réflexion. Si les performances sont critiques, vous pouvez commencer par comparer les types et, s'ils correspondent, passer aux définitions des membres. Après avoir vérifié les définitions de type et de membre et si tout est égal à ce point, vous pouvez aller plus loin en examinant l'IL réelle de chaque méthode en la faisant passer par GetILAsByteArray méthode. Encore une fois, vous allez trouver des différences même si tout est identique mais compilé avec des drapeaux un peu différents ou une version différente du compilateur. Je dirais que la meilleure solution est d'utiliser un outil d'intégration continue qui marque le build avec le numéro de changeset de votre contrôle de source (vous en utilisez un, n'est-ce pas ?).

Un article connexe

3voto

Florian Points 11

Vous pouvez utiliser MonoCecil et lui apporter une petite modification pour que le problème soit résolu. Je l'ai fait, vous pouvez lire comment ici : http://groups.google.com/group/mono-cecil/browse_thread/thread/6ab42df05daa3a/49e8b3b279850f13#49e8b3b279850f13

Salutations Florian

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