Получить код из С# DLL Динамически

Я хотел бы узнать, одинаковы ли DLL (возможно, скомпилированные на разных машинах). Для этого я загружал DLL и вычислял MD5, который не удался для DLL, сбой на разных машинах (но имел тот же источник). Кажется, это связано с другими метаданными, которые добавляются во время компиляции (как кто-то упоминал здесь).

Я подумал об обратном проектировании всей DLL и посмотрел, соответствует ли код, однако у меня есть две проблемы с этим:

  • Я могу найти инструменты, которые это делают, я не могу найти библиотеку С# или что-то подобное, что делает то, что мне нужно.
  • Я не уверен на 100%, если декомпилированный источник будет таким же на источнике, скомпилированном на разных машинах.

Любые подсказки, подсказки и указатели будут оценены.

Ответ 1

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

Затем мы добавляем контрольную сумму в описание DLL. Это позволило нам скомпилировать DLL на разных машинах, но поскольку их источник был тем же, была получена та же контрольная сумма.

Спасибо за предоставленные ответы, они очень полезны.

Ответ 2

Возможно, вы правы - это могут быть метаданные. Я не думаю, что это, скорее всего, самая вероятная возможность.

Другая причина, по которой DLL различны, вероятно, что они были скомпилированы против разных версий .NET или, возможно, MONO.

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

Если программист разворачивает цикл вручную и перекомпилирует, что оптимизация, которую компилятор делал в любом случае, - presto, два разных источника с одинаковым выходом.

Лучшим вопросом будет то, что вы надеетесь узнать, сравнив две библиотеки DLL. Если это строго ради обучения, это здорово и заслуживает похвалы - однако, объем знаний, который вам понадобится для значимого изучения этого, достаточно высок. Вы, скорее всего, найдете лучшие результаты, изучив общие, более применимые методы С#/. Net.

Ответ 3

Подпишите эту сборку, используя сильное имя, и вы сможете быть абсолютно уверены, что две или более сборки являются одинаковыми - или разными - потому что они имеют одну и ту же версию сборки, тот же токен открытого ключа и так.

Я сомневаюсь, что у двух разных разработчиков был бы повторный закрытый ключ, если исходный код и проект Visual Studio не совпадают.

Ответ 4

  • Являются ли эти библиотеки вашими, это ваш код?
  • Установлены ли они вашим установщиком или независимо, и вы просто проверяете их?

Если вы каким-либо образом можете контролировать их первоначальную установку на целевом компьютере, вы можете сделать водяной знак с бедными людьми с использованием обычных старых DLL-ресурсов.

Прикрепите двоичный ресурс с вашим собственным содержимым к каждой версии установленной DLL, а затем проверьте его. Это очень важно, если вы вложили public static readonly class Something{ public static SomeData MyImportantInformation = ...; } в каждый код и прочитали его во время выполнения или как если бы вы использовали [Атрибуты] с данными по некоторым классам и читали их через отражение - но использование двоичных ресурсов имеет 2 крошечных преимущества:/p >

  • вы можете добавить/удалить resourecs из DLL после, который был создан (немного похож на инструмент ILMerge)
  • вы можете легко считывать ресурсы из собственного кода так же легко, как и из управляемого, и для их чтения вы можете загружать DLL очень ограниченным и ресурсосберегающим способом.

Помните, что я имею в виду "ресурсы низкого уровня", такие как манифест, который обычно помещает ресурс в значки слота # 0 или .exe/.dll.

В двоичных ресурсах:

http://www.codeproject.com/Articles/4221/Adding-and-extracting-binary-resources

И на управляемых встроенных ресурсах, которые проще в использовании:

http://keithelder.net/2007/12/14/how-to-load-an-embedded-resource-from-a-dll/ fooobar.com/info/302773/...

Вы можете добавить добавление/изменение ресурсов в сценарии сборки, чтобы убедиться, что в каждой опубликованной версии добавлена ​​другая/правильная информация. Разумеется, если вы контролируете процесс сборки, тогда вы можете как можно лучше запустить вышеупомянутый ILmerge, чтобы поместить все в любую DLL. Хотя большая часть этого будет работать, но в целом, я думаю, что это слишком много, и если это сделано неправильно будет нарушать любые сигнатуры безопасности, если он изменяет DLL после его подписания. Это нужно сделать до этого.

Если вы контролируете процесс сборки, вы можете просто поместить необходимую информацию для управления версиями в код как статические данные класса или просто как атрибуты на уровне сборки или (...)

Или почему бы вам просто не использовать номера версий для дифференцировать версии?:) т.е. семантическое управление версиями?

С другой стороны, если вы работаете с не-вашими DLL файлами, и если у вас нет контроля над их развертыванием, то вы находитесь на жестких основаниях. Как говорили другие, компиляторы могут применять много разных трюков во время компиляции, но, пожалуйста, обратите внимание: у них есть как юридические, так и логические ограничения на то, что они могут сделать с скомпилированным кодом.

Пример "логических" ограничений:
- они могут изменять инструкции, но не могут изменять общий смысл и (побочные) эффекты - они могут изменять как компоновку кода и данных, так и структуру, но не таким образом, чтобы изменить алгоритмы их обработки и т.д.

Пример "юридических" ограничений:
- им не разрешено удалять общедоступный символ (public = видимый другими модулями кода, то есть в .Net, который охватывает: общедоступные и защищенные, а иногда и внутренние и частные) - им запрещено изменять имя любого общедоступного символа - им запрещено изменять подпись любого общедоступного символа и т.д.

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

Для самого тривиального примера: загрузите DLL через отражение и сканируйте все классы для своих имен публичных и непубличных пользователей. Затем либо вычислите хэш по этому набору строк, либо просто используйте весь stringset, я бы, вероятно, считался в кбайтах максимум. Если в код внесено большое изменение, почти наверняка будут добавлены или удалены некоторые поля/методы. Для небольших изменений вы также можете сканировать подписи методов: добавлять списки параметров и типы параметров и возвращать значения в пул. Немного больше работы и больше вероятности обнаружения изменения.

Для нетривиального изменения: вы можете попробовать сканировать ILCode методов и обнаруживать в нем структуры. Компиляторы могут встроить, а иногда удалить методы/петли/etc, но общая структура сохраняется. Конкретный блок кода выполняется n-раз здесь или там, ветки на своем месте, но, возможно, с повязанными сторонами и т.д. Однако обнаружить структуры управления непросто, а сравнение кода еще сложнее. Для некоторых кодов он может дать вам окончательный ответ "точно такой же", но во много раз вы получите "не то же самое", даже если они есть. Некоторые ключевые слова по этому вопросу - это... дубликат или детектор плагиата. Так началось исследование таких вещей:) см. Т.е. https://stackoverflow.com/info/546487/tools-to-identify-code-duplications, хотя я не знаю, упомянули ли упомянутые инструменты сканирование кода или "байты"..