Если после статьи «Конфуз, сэр! Добываем код из ConfuserEx без готовых деобфускаторов» тебе не надоели .NET-обфускаторы, сегодня мы перейдем к обсуждению еще более зловредного представителя этого семейства — Eazfuscator.NET. Зловредность его заключается в том, что, помимо уже встречавшегося нам ранее джентльменского набора фич вроде обфускации control flow, шифрования констант, строк и имен идентификаторов, в нем присутствует вполне себе натуральная виртуальная машина. Наподобие тех, которые мы встречали во взрослых защитах Enigma, Obsidium, Themida или даже в VMProtect.
До этого мы разбирали способ сокрытия IL-кода путем шифрования отдельных классов или методов с расшифровкой непосредственно перед JIT-компиляцией, что делало его уязвимым для реверса на этом этапе. В рассматриваемом же случае набор IL-инструкций преобразуется в шифрованную последовательность псевдокоманд шитого кода, пошагово исполняемую встроенным интерпретатором. Разумеется, это чертовски замедляет работу приложения, однако на что не пойдешь ради приватности кода? Ну что же, давай посмотрим, что можно предпринять в столь запущенном случае.
Итак, у нас есть некое приложение. Требуется отследить в нем вызов определенного диалогового окна и по возможности научиться управлять им. К сожалению, Eazfuscator пока еще не детектируется стандартными средствами, Detect It Easy видит в нем обычное обфусцированное .NET-приложение PE32:
Operation system: Windows(95)[I386, 32-bit, GUI]
Linker: Microsoft Linker(6.0)
Compiler: VB.NET
Language: VB.NET
Library: Microsoft Edge Chromium WebView
Library: .NET Framework(CLR 4.0.30319)
Sign tool: Windows Authenticode(2.0)[PKCS #7]
(Heur)Protection: Obfuscation[Virtualization Calls encrypt Anti-ILDASM Bad namings Math inversions]
(Heur)Protection: Anti analysis[Anti-debug]
Overlay: Binary(Store)[Offset=0x00321c00,Size=0x2978]
Certificate: WinAuth(2.0)[PKCS #7]
De4dot детектирует некий неизвестный Unknown Obfuscator, поэтому наличие Eazfuscator нам придется определять эмпирически, по внешнему виду кода. Загрузим исследуемое приложение в отладчик dnSpy.

Бросается в глаза упомянутый выше базовый набор обфускатора — нечитаемые имена, неуклюжая обфускация control flow с добавлением бессмысленных условных операторов и почти полное отсутствие видимых строковых констант. De4dot слегка причесывает код, убирая лишние условные операторы и меняя сложночитаемые длинные имена на нумерованные классы и методы, однако весьма дорогой ценой — программа при этом теряет работоспособность.
По характерному виду обфусцированных имен (#=..., а внутри набор символов, маскирующийся под Base64) можно предположить, что это наш пациент. К слову сказать, имена эти отнюдь не бессмысленны. Они имеют разную длину, и некоторые из них повторяются в весьма осмысленном контексте, что дает основание предполагать: информация об их исходном виде не потеряна и при желании восстановима. Так и есть, умные люди провели исследование и даже попытались написать утилиту для их восстановления. К сожалению, практически эти наработки бесполезны, поскольку имена зашифрованы AES, ключ к которому, скорее всего, имеется только у разработчиков.
Так что не будем отвлекаться на эту тему — решению нашей задачи она помогает лишь опосредованно. Гораздо более интересна задача деобфускации строк. При видимом отсутствии читаемых строковых констант код изобилует вызовами с константами номерными.

Благодаря нашему опыту работы с другими обфускаторами нас начинают терзать смутные сомнения, что вызовы метода #=zjsc8ywR05iBjsM$TSzzy5Bfjq_c3. и есть обращение к текстовым константам. Причем простые манипуляции с отладчиком это подтверждают (еще одна хорошая новость — Eazfuscator в отладке программы нам пока что совершенно не препятствует). И снова приятная неожиданность: нам не придется самим декодировать строковые константы, поскольку умные люди и тут постарались до нас — инструмент EazFixer в сочетании с de4dot прекрасно расшифровывает строки и ресурсы до читаемого вида. К сожалению, ценой той же самой потери работоспособности деобфусцированного модуля, поэтому данный метод годится только для анализа кода.
Однако все это, так сказать, необязательная косметика: мы проделывали подобное ранее с другими обфускаторами. Вернемся к самому главному моменту нашего обсуждения — работе с виртуализованным кодом. Как я уже говорил, по условию задачи нам нужно разобраться с вызовом определенного диалогового окна, при этом код формы присутствует в кое‑как деобфусцированном листинге, однако непосредственный его вызов в коде отсутствует. На него можно поставить точку останова и попробовать понять, как такое происходит. Посмотрим внимательно на стек возвратов по достижении этой точки останова.

Как видишь, требующийся нам метод вызывается динамически через Invoke. MethodBase и параметры конструируются во время исполнения длинной цепочки вложенных вызовов. Поставив на этот Invoke точку останова, мы обнаруживаем множество последовательных вызовов самых разнообразных методов — налицо явные признаки виртуальной машины, про которую нам было известно с самого начала.
Продолжение доступно только участникам
Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».
Присоединяйся к сообществу «Xakep.ru»!
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
