Определите, были ли сборки.NET построены из одного источника
Кто-нибудь знает способ сравнения двух сборок.NET, чтобы определить, были ли они собраны из "одинаковых" исходных файлов?
Я знаю, что есть несколько разностных утилит, таких как плагин для Reflector, но я не заинтересован в просмотре различий в графическом интерфейсе, я просто хочу автоматизированный способ сравнить набор двоичных файлов, чтобы увидеть, были ли они созданы из одинаковые (или эквивалентные) исходные файлы. Я понимаю, что несколько разных исходных файлов могут создавать один и тот же IL, и понимаю, что процесс будет чувствителен только к различиям в IL, а не к исходному источнику.
Основным препятствием для простого сравнения потоков байтов для двух сборок является то, что.NET включает в себя поле под названием "MVID" (идентификатор версии модуля) сборки. Похоже, что это имеет различное значение для каждой компиляции, поэтому, если вы создадите один и тот же код дважды, сборка будет другой.
С этим связан вопрос: кто-нибудь знает, как заставить MVID быть одинаковым для каждой компиляции? Это избавило бы нас от необходимости иметь процесс сравнения, который нечувствителен к различиям в значении MVID. Согласованный MVID будет предпочтительным, поскольку это означает, что можно использовать стандартные контрольные суммы.
Основанием для этого является то, что сторонняя компания несет ответственность за независимую проверку и подписание наших выпусков до того, как нам разрешат выпустить в производство. Это включает в себя просмотр исходного кода. Они хотят независимо подтвердить, что предоставляемый им исходный код соответствует двоичным файлам, которые мы ранее создали, протестировали и в настоящее время планируем развернуть. Мы ищем процесс, который позволит им независимо собрать систему из источника, который мы им поставляем, и сравнить контрольные суммы с контрольными суммами для двоичных файлов, которые мы тестировали.
КСТАТИ. Обратите внимание, что мы используем непрерывную интеграцию, автоматические сборки, контроль исходного кода и т. Д. Проблема не связана с отсутствием внутреннего контроля над тем, какие исходные файлы вошли в данную сборку. Проблема заключается в том, что третья сторона несет ответственность за проверку того, что источник, который мы им предоставляем, производит те же двоичные файлы, которые мы протестировали и планируем использовать в Production. Они не должны доверять ни одной из наших внутренних систем или элементов управления, включая сервер сборки или систему контроля исходного кода. Все, о чем они заботятся, - это получить исходный код, связанный со сборкой, выполнить сборку самостоятельно и убедиться, что выходные данные соответствуют тому, что мы говорим о развертывании.
Скорость выполнения решения сравнения не особенно важна.
Спасибо
7 ответов
Это не слишком болезненно использовать инструменты командной строки, чтобы отфильтровать MVID и метки даты и времени из текстового представления IL. Предположим, file1.exe и file2.exe созданы из одних и тех же источников:
c: \ temp> ildasm / all / text file1.exe | найти /v "Отметка даты и времени:" | найти /v "MVID"> file1.txt
c: \ temp> ildasm / all / text file2.exe | найти /v "Отметка даты и времени:" | find /v "MVID"> file2.txt
c: \ temp> fc file1.txt file2.txt
Сравнение файлов file1.txt и FILE2.TXT
FC: различий не обнаружено
При сравнении библиотек классов с ILDasm v4.0.319.1 создается впечатление, что база изображений не инициализирована. Чтобы избежать несоответствий, используйте пересмотренное решение:
ildasm /all /text assembly.dll
| find /v "// Time-date stamp:"
| find /v "// MVID:"
| find /v "// Checksum:"
| find /v "// Image base:"
> assembly.dasm
Точка входа (база изображений) на самом деле представляет интересную информацию для исполняемых сборок, и ее нужно будет тщательно проверять. Внедрение новой базы изображений - это обычный способ заставить программу делать что-то совсем другое. В моем случае я пытаюсь проверить согласованность многопоточных сборок, поэтому можно безопасно пропустить точку входа.
Замечание по производительности: я взял 8MB DLL, созданную для AnyCPU, и запустил ILDasm. Получившийся файл имел размер 251 МБ и занял несколько минут. Примерно 32x размер был произведен.
Я использовал решение Джерри Керри на сборках.Net 4 и обнаружил, что теперь есть третий элемент, который будет меняться в каждой сборке: контрольная сумма. Не удивительно ли найти контрольную сумму внутри сборки? Я думаю, что добавление контрольной суммы файла внутри этого файла изменит контрольную сумму...
В любом случае, измененная команда:
ildasm /all /text "assembly.dll"
| find /v "// Time-date stamp:"
| find /v "// MVID:"
| find /v "// Checksum:"
> assembly.dasm
Обратите внимание, что я также немного изменил строки поиска, добавив косую черту, чтобы избежать непреднамеренного совпадения. Строки этой команды должны запускаться вместе в одной строке, разделяться для удобства чтения. Имена файлов будут нуждаться в двойных кавычках вокруг них, если они содержат пробелы.
Есть несколько способов сделать это в зависимости от объема работы, которую вы готовы выполнять, а также важности производительности и / или точности. Один из способов, как указал Эрик Дж., - сравнивать сборки в двоичном формате, исключая части, которые меняются при каждой компиляции. Это простое и быстрое решение, но оно может дать вам много ложных негативов. Одним из лучших способов является углубление с помощью отражения. Если производительность критична, вы можете начать со сравнения типов и, если они совпадают, перейти к определениям элементов. После проверки типов и определений элементов, и если все равно этому пункту, вы можете пойти дальше, изучив фактический IL каждого метода, пройдя его GetILAsByteArray
метод. Опять же, вы найдете различия, даже если все то же самое, но скомпилировано с немного другими флагами или другой версией компилятора. Я бы сказал, что лучшим решением является использование инструментов непрерывной интеграции, которые помечают сборку номером набора изменений в вашем контроле исходного кода (вы используете один, верно?).
Вы можете использовать MonoCecil и внести в него небольшие изменения, чтобы решить проблему. Я сделал это, вы можете прочитать, как здесь: http://groups.google.com/group/mono-cecil/browse_thread/thread/6ab42df05daa3a/49e8b3b279850f13
С уважением Флориан
Другое решение для рассмотрения:
Информация исходного кода сохраняется, когда двоичные файлы компилируются в режиме отладки. Затем вы можете проверить, соответствует ли pdb exe и соответствуют ли строки pdb исходному коду.