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