Определите, были ли сборки .NET построены из одного источника

Кто-нибудь знает, как сравнить две сборки .NET, чтобы определить, были ли они созданы из «одинаковых» исходных файлов?

Я знаю, что есть некоторые доступные утилиты для разнесения, такие как плагин для Reflector, но мне не интересно просматривать различия в графическом интерфейсе, я просто хочу автоматизированный способ сравнить коллекцию двоичных файлов, чтобы узнать, были ли они созданы из одинаковые (или эквивалентные) исходные файлы. Я понимаю, что несколько разных исходных файлов могут создавать один и тот же IL и понимать, что процесс будет чувствителен только к различиям в IL, а не к исходному источнику.

Основным препятствием для простого сравнения streamов байтов для двух сборок является то, что .NET включает в себя поле под названием «MVID» (идентификатор версии модуля) сборки. Кажется, что у каждой компиляции другое значение, поэтому, если вы создадите один и тот же код дважды, assembly будет отличаться.

Связанный с этим вопрос: кто-нибудь знает, как заставить MVID быть одинаковым для каждой компиляции? Это позволит нам избежать процесса сравнения, который нечувствителен к различиям в значении MVID. Согласованный MVID будет предпочтительнее, поскольку это означает, что могут использоваться стандартные контрольные суммы.

Основой этого является то, что сторонняя компания несет ответственность за независимое рассмотрение и отключение наших релизов до того, как нам разрешат выпустить в Production. Это включает в себя проверку исходного кода. Они хотят самостоятельно подтвердить, что исходный код, который мы им даем, соответствует двоичным файлам, которые мы ранее построили, протестировали и в настоящее время планируем развернуть. Мы ищем процесс, который позволяет им самостоятельно строить систему из источника, который мы им поставляем, и сравнивать контрольные суммы с контрольными суммами для бинарных файлов, которые мы тестировали.

КСТАТИ. Обратите внимание, что мы используем непрерывную интеграцию, автоматические сборки, контроль источника и т. Д. Проблема не связана с внутренним отсутствием контроля над исходными файлами в данной сборке. Проблема в том, что третья сторона несет ответственность за проверку того, что источник, который мы им предоставляем, производит те же бинарные файлы, которые мы тестировали, и планируем ввести в Production. Они не должны доверять ни одной из наших внутренних систем или элементов управления, включая сервер сборки или систему управления исходным кодом. Все, о чем они заботятся, это получение источника, связанного с сборкой, выполнение самой сборки и проверка того, что результаты соответствуют тому, что мы говорим, мы развертываем.

Скорость выполнения решения сравнения не имеет особого значения.

благодаря

Нелегко использовать инструменты командной строки для фильтрации MVID и штампов даты из текстового представления IL. Предположим, файлы file1.exe и file2.exe построены из тех же источников:

c: \ temp> ildasm / all / text file1.exe | find / v “Дата штампа:” | find / v “MVID”> file1.txt

c: \ temp> ildasm / all / text file2.exe | find / v “Дата штампа:” | find / v “MVID”> file2.txt

c: \ temp> fc file1.txt file2.txt

Сравнение файлов file1.txt и FILE2.TXT

FC: нет различий

При сравнении библиотек classов с 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 

Точка входа (база изображений) – фактически интересная информация для исполняемых сборок и должна быть проверена тщательно. Внедрение новой базы изображений – это общий способ сделать программу чем-то совершенно другим. В моем случае я пытаюсь проверить последовательность многопоточных compilationов, поэтому безопасно пропустить точку входа.

Заметка о производительности: я взял 8 МБ DLL, которая была построена для AnyCPU, и запускала ILDasm. Результирующий файл был размером 251 МБ и потребовалось несколько минут. Размер был составлен примерно в 32 раза.

Я использовал решение Jerry Currry на assemblyх .Net 4 и выяснил, что теперь есть третий элемент, который будет зависеть от каждой сборки: контрольная сумма. Разве не удивительно находить контрольную сумму внутри сборки? Я думаю, что добавление контрольной суммы файла внутри этого файла изменит контрольную сумму …

Во всяком случае, измененная команда:

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

Обратите внимание, что я также немного изменил строки поиска, добавив косые черты, чтобы избежать непреднамеренных совпадений. Строки этой команды должны запускаться вместе в одной строке, разделенной на читаемость. Имена файлов потребуют двойных кавычек вокруг них, если они содержат пробелы.

Существует несколько способов сделать это в зависимости от объема работы, которую вы готовы сделать, и важности производительности и / или точности. Один из способов, как указал Эрик Дж., – сравнить сборки в двоичном формате, исключая части, которые изменяются при каждой компиляции. Это решение легко и быстро, но может дать вам много ложных негативов. Один лучший способ – развернуть, используя reflection. Если производительность критическая, вы можете начать с сравнения типов и, если они совпадают, перейти к определениям членов. После проверки типов и определений членов, и если все будет равно этой точке, вы можете пойти дальше, исследуя фактический IL каждого метода, GetILAsByteArray его через метод GetILAsByteArray . Опять же, вы найдете различия, даже если все одно и то же, но скомпилировано с помощью немного разных флагов или другой версии компилятора. Я бы сказал, что лучшим решением является использование инструментов непрерывной интеграции, которые маркируют сборку с номером набора изменений вашего исходного элемента управления (вы используете один, правильно?).

Связанная статья

вы можете использовать MonoCecil и дать ему небольшую модификацию, чтобы решить проблему. Я сделал это, вы можете прочитать, как здесь: http://groups.google.com/group/mono-cecil/browse_thread/thread/6ab42df05daa3a/49e8b3b279850f13#49e8b3b279850f13

С уважением Флориан

Здесь вы можете использовать Reflector Diff AddIn.

Другое решение:

Информация исходного кода сохраняется, когда двоичные файлы скомпилированы в режиме отладки. Затем вы можете проверить, соответствует ли pdb exe, и если строки pdb соответствуют исходному коду.

  • Эффективное умножение матрицы 4x4 (C vs assembly)
  • Как скомпилировать и запустить программу C в Sublime Text 2?
  • Что регистрирует сохранение в соглашении вызова ARM C?
  • Как загрузить сборку во время выполнения перед событием AssemblyResolve?
  • Как объединить несколько сборок в один?
  • Сколько циклов процессора требуется для каждой инструкции сборки?
  • .Net: Запуск кода при загрузке сборки
  • Как извлечь сборку из GAC?
  • Дополнительная информация о макете памяти исполняемой программы (процесса)
  • Не удалось загрузить файл или сборку HRESULT: 0x80131515 (При добавлении controllerа в проект MVC с ссылками на сборку на сетевом диске)
  • C #: зачем подписывать сборку?
  • Давайте будем гением компьютера.