Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #65, АПРЕЛЬ 2006 г.

штурм зимнего .net'а

N|M{INT3 TEAM} (NIM@INT3.RU)

Спецвыпуск: Хакер, номер #065, стр. 065-042-6


Вот распаковка закончена. Единственное оставшееся действие — пропатчить функцию (в уже распакованном файле, конечно ;)) jungle.Decompiler.NET.Licensing::.ctor(string __0, class jungle.Decompiler.NET.Licensing.License __1). Пропатчить нужно всего в шести местах по меткам: IL_0043, IL_004a, IL_0051, IL_00f4, IL_00f6, IL_0102, заменив ldc.i4.0 на ldc.i4.1. Я только что перечислил флаги класса License: fIsLicenseKeyValid, fIsSignatureValid и fIsLicenseKeyValidComputed. Все готово. Теперь обфускатор работает как нужно:

ПОДВОДИМ ИТОГИ. ВСЕГО ЗА НЕСКОЛЬКО ЧАСОВ ПРОГРАММА СТОИМОСТЬЮ $550 БЫЛА ЗНАЧИТЕЛЬНО УЛУЧШЕНА ;)

конечно, нужно раскрыть хитрости,

использованные чтобы затруднить анализ кода. Я уже упоминал, что в методе ab.az::ag2 используется динамическое создание доменов. Так вот автор определил класс ProxyControl, посредством которого происходили вызовы методов оригинального ехе из загрузчика и наоборот. Эта технология называется Remouting, и она позволила замусорить CallStack, причем при работе в отладчике я не мог понять, откуда вызываются методы, — адреса возврата уходили куда-то в неуправляемый код. Больше всего я удивился в тот момент, когда ковырялся в загрузчике и вдруг неожиданно выскочила форма (см. на рисунке), которая была определена в самом загрузчике ab.ap.cs. Лечится это просто: удаляются функции создания динамических доменов System.AppDomain::CreateDomain и ликвидируются сопутствующие им динамические создания объектов (C#): this.ag5 = (av) domain1.CreateInstanceAndUnwrap(type1.Assembly.GetName().Name, type1.FullName);. Для замены лучше написать просто this.ag5 = new type1. На крайний случай можно написать так: System.AppDomain::CreateInstance(type1.Assembly.GetName().Name, type1.FullName), — и тогда объект будет создан в текущем домене плюс исчезнут все заморочки.

Вторая примененная хитрость заключается в хитром вызове функций, компрометирующие названия которых привлекают внимание. Предварительно создается поле с типом Type, класс Type поддерживает любые динамические махинации, например вызов метода или чтение поля класса. Это можно наблюдать в a4.a8::.cctor, создается Type a8.ai4 = Type.GetType("System.Security.Cryptography.TripleDESCryptoServiceProvider"); потом создается объект, описывающий конкретный метод: MethodBase a8.ai0 = a8.ai3.GetGetMethod(true); Этот метод вызывается вот так: a8.ai0.Invoke(). Такая технология называется рефлекцией (пространство имен — System.Reflection), но она имеет большой недостаток — очень непроизводительный способ вызова методов, который, соответственно, годится только на этапе инициализации, что, в принципе, устраивает автора защиты.

Следующая хитрость — это метод хранения лицензии. Классы, помеченные атрибутом [Serializable], могут быть сохранены в потоке (stream) или восстановлены из него. Притом сохраняются значения полей класса и информация о сборке. Есть маленький нюанс, благодаря которому этот метод используется в защите: при изменении версии сборки объект, сохраненный ранее, уже не может быть восстановлен. Получается, что если совершил маленькую оплошность, ты получаешь уникальный шанс потратить немало времени на ее выявление. Автор использует данную технологию по отношению к некоторым классам, в том числе к классу Licensing.

Назад на стр. 065-042-5  Содержание  Вперед на стр. 065-042-7