Содержание статьи
info
О принципах взлома приложений, защищенных протектором Enigma, читай в статьях «Больше не энигма. Ломаем защиту приложений Enigma x64 актуальных версий» и «Триальный конь. Как сломать trial, защищенный Enigma Protector».
C легкой руки Microsoft одной из самых популярных платформ для программирования в настоящее время стала .NET. Огромное количество инструментов, библиотек и документации обеспечивают простоту вхождения даже для самых начинающих кодеров, а кросс‑платформенность и все более совершенная оптимизация кода делают ее одним из основных стандартов написания коммерческого софта. Как следствие, инструментов для взлома и реверс‑инжиниринга под эту платформу тоже успели создать немало. Среди них dnSpy, ILspy, ILdasm, Dile, SAE и многие другие, имя им — легион!
Задача для реверсеров упрощается тем, что по умолчанию скомпилированная программа фактически содержит свой исходник: имена символов хранятся в явном виде, а кросс‑платформенный IL-псевдокод легко восстанавливается до исходных синтаксических конструкций C# или VB, из которых он был получен при компиляции. Соответственно, взлом такой программы для начинающего хакера — одно удовольствие: достаточно загрузить ее в dnSpy, и вот она, на блюдечке в своих исходниках, для удобства даже окрашенных в приятные цвета. Отлаживай и правь как хочешь, как будто сам эту программу и написал!
Немного теории
Разумеется, производители софта мириться с подобным положением дел не могут, и на очередном витке конфронтации между хакерами и протекторами было разработано много инструментов, препятствующих восстановлению исходного кода из IL-сборки. Грубо говоря, все подобные инструменты используют три основных принципа:
- сокрытие (шифрование, компрессия и так далее) .NET-метаданных и IL-кода с восстановлением только в краткий миг JIT-компиляции;
- обфускация IL-кода, то есть преднамеренное запутывание его логики, борьба с читаемостью текстовых строк и имен символов, чтобы понять логику работы восстановленного IL-кода было сложнее;
- комбинация двух предыдущих категорий.
Сегодня мы поговорим о методах из первой категории. В принципе, наиболее простой и дубовый способ оградить программу от ILDasm — скомпилировать ее с атрибутом SupressIldasmAttribute
. Понятное дело, это защита от честных людей, поскольку такая сборка превосходно детектируется как .NET-приложение, декомпилируется другими инструментами, а данный атрибут с полпинка снимается в CFF Explorer или, при изрядной сноровке, в простом HEX-редакторе. Более интересно «завернуть» метаданные в обычное нативное приложение, формирующее и запускающее .NET-сборку на лету.
В этом случае никакие детекторы не распознают в ней .NET, если их предварительно не обучили этому трюку, а декомпиляторы и отладчики, с ходу не увидевшие в программе метаданных, обломаются при загрузке. С помощью dnSpy можно попытаться исследовать такое приложение, однако при прерывании он навряд ли сможет восстановить и трассировать код дальше, что делает такую отладку бесполезной. Как быть в таком случае?
Самый простой способ — воспользоваться утилитой MegaDumper (или даже ее более продвинутой версией ExtremeDumper). Если .NET сформирован и запущен по всем правилам, то он корректно распознается упомянутыми утилитами именно как .NET-процесс, и при нажатии кнопочки .
дампится как стандартное .NET-приложение. Правда, вовсе не факт, что оно будет запускаться. Чтобы привести его в запускаемый вид, придется проделать определенные телодвижения, в зависимости от продвинутости протектора. Тем не менее метаданные .NET и IL в такой сдампленной сборке будут доступны для декомпиляции и анализа. Можно убедиться в этом, открыв сборку, например, в CFF Explorer. Однако я специально сделал оговорку «если». Попробуем разобраться, почему подобное может не сработать.
Для этого постараюсь коротко в двух словах напомнить принцип функционирования .NET-приложения для тех, кто забыл матчасть. Несмотря на то что сборка состоит из метаданных и кросс‑платформенного IL-кода, при выполнении приложения он не интерпретируется, а компилируется в весьма оптимизированный нативный код целевого процессора и целевой операционной системы. Делается это непосредственно при загрузке блока кода один раз, впоследствии будет выполняться уже скомпилированный нативный код метода. Сам процесс называется JIT-компиляция (Just In Time, «временная компиляция на лету»). То есть если прервать программу в произвольный момент в отладчике типа x64dbg, то процесс будет остановлен именно во время исполнения такого временно скомпилированного нативного кода.
Трассировать, отлаживать и реверсировать его, конечно, можно, но целесообразность этого сомнительна. Нас интересует другой подход — поймать и сдампить уже восстановленный фрагмент IL-кода перед его JIT-компиляцией. Логика подсказывает, что, если мы хотим сделать это вручную, нам надо найти в отладчике изначальную точку входа в JIT-компилятор. Самое простое — отыскать метод SystemDomain::
в библиотеке clr.
(или mscorwks.
для более старых версий .NET). Обычно для подобных вещей рекомендуют использовать WinDbg и его расширение SOS, но я для примера покажу, как это делать в x64dbg.
Ищем JIT-компилятор
Итак, загрузив нужное приложение в отладчик, мы с неприятным удивлением обнаруживаем, что библиотека clr.
отсутствует в списке отладочных символов. Значит, ее придется загрузить дополнительно, предварительно отыскав глубоко в недрах подкаталогов системной папки Windows. Найдя и загрузив clr.
(попутно загрузится несколько библиотек), мы снова с раздражением обнаружим, что метод SystemDomain::
отсутствует в правом списке экспорта. Ну что ж, по счастью, x64dbg предоставляет прекрасную возможность загрузить отладочные символы прямо с майкрософтовского сервера — для этого нужно щелкнуть правой клавишей мыши на clr.
и выбрать соответствующий пункт в контекстном меню.
Подождав некоторое время, мы увидим, что список в правой части окна отладчика изрядно увеличился и искомый метод SystemDomain::
в нем уже присутствует. Ставим на него точку останова и запускаем программу. В момент останова на этом методе дотнетовские метаданные чаще всего уже расшифрованы, распакованы и их можно дампить в файл хоть MegaDumper’ом, хоть Scylla из самого дебаггера. Однако этого тоже может оказаться недостаточно. Попробуем копнуть чуть глубже и выйти на исходный JIT-компилятор.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»