Вступление
В этой статье я хочу поделиться с уважаемым хабраобществом своим опытом анализа и модификации обфусцированной .NET сборки на примере COMET-библиотеки PokeIn.
![Reverse Engineering](http://palisade.plynt.com/images/defend-reverse-engineering.jpg)
Несколько дней назад я заинтересовался COMET решениями для ASP.NET и нашел несколько интересных библиотек, среди которых некогда бывшая бесплатной PokeIn. Очевидно она пользовалась некоторой популярностью, так как авторы перевели ее из разряда open source в платную. На сайте бибилиотеки есть возможность скачать бесплатную версию с некоторыми ограничениями, среди которых, пожалуй, самое важное — это ограничение в 10 одновременных соединений. С ним мы и будем бороться.
Декомпиляция
Первый инструмент для реверс-инжиниринга и анализа .NET сборок — это всем известный Reflector. Качаем с сайта PokeIn бесплатную версию библиотеки, ищем в архиве сборку для .NET Framework и запускаем Reflector. Тут нас ждет первое разочарование: Reflector напрочь отказывается открывать сборку.
![Reflector Fail](https://habrastorage.org/storage/habraeffect/f9/3c/f93c143ad0483e8a40fca7ee01626415.png)
Окей, закрываем Reflector и вспоминаем про ildasm.exe — утилита из Windows SDK для декомпиляции .NET сборок в MSIL-код (Microsoft Intermediate Language). Это даст нам конечно более низкоуровневый код и с ним будет не так удобно работать, но, на самом деле, это не намного сложнее.
Итак, запускаем ildasm, открываем нашу сборку… и опять фейл: «Protected module — cannot disassemble».
![ILDasm Fail](https://habrastorage.org/storage/habraeffect/0c/8f/0c8fff85a8ee9fa7d1cbe8820fb95181.png)
Это означает что сборка скомпилирована с атрибутом SupressIldasmAttribute. Чтобы декомпилировать данную сборку нам нужно избавиться от этого атрибута. Я для этого использовал бесплатную утилиту для редактирования PE файлов CFF Explorer. Она имеет полную поддержку метаданных .NET сборок. Открываем наш файл и ищем метаданные: '.NET Directory'/'MetaData Streams'/'#~'/'Tables'. В таблице метаданных ссылок на типы (TypeRef) находим ссылку на тип SupressIldasmAttribute и удаляем ее путем установки полей Name и Namespace в 0.
![CFF Explorer Win](https://habrastorage.org/storage/habraeffect/2f/d9/2fd9f241bcf590239cfd2cf2113b2438.png)
Теперь мы можем открыть сборку в ildasm'е и просмотреть MSIL-код, уже неплохо. Но в Reflector'е наш файл все еще не открывается. Для того чтобы сделать это, сохраняем MSIL в файл командой "ildasm.exe pokein.dll /source /out:pokein.il" и пересобираем сборку при помощи утилиты ilasm, которая входит в поставку .NET Framework: "ilasm.exe pokein.il /dll /out:pokein.dll". К сожалению, выгоды от этого мало, так как большинство обфусцированных методов все еще будут недоступны, а список класов\полей\методов можно посмотреть в Object Browser'е.
Анализ кода
Приступим к анализу кода. Скудная документация и пример из архива позволяют понять, что основная работа происходит в статическом классе PokeIn.Comet.CometWorker. При более детальном его изучении находим статическое свойство ActiveClientCount, название которого намекает, что оно может использоваться при проверке ограничения на количество клиентов, а также несколько перегруженных методов Bind, очевидно вызывающихся при подключении нового клиента.
Продолжаем работать с il-файлом. При поиске по строке ActiveClientCount находим несколько вызовов свойства следующего вида:
IL_0007: call int32 PokeIn.Comet.CometWorker::get_ActiveClientCount()
IL_000c: ldc.i4.s 10
IL_000e: ble IL_0027
Разберем этот код по строчкам:
IL_0007: вызывает getter свойства ActiveClientCount и помещает результат в стек
IL_000c: помещает в стек число 10
IL_000e: если первый операнд из стека меньше или равен второму, переход по адресу IL_0027
Что характерно, эти вызовы находятся в методах Bind и DynamicBind, что свидетельствует, что мы на правильном пути.
Отладка MSIL
Следующий этап необязательный, но мне всегда интересно посмотреть как это работает вживую, поэтому попробуем запустить сборку в режиме отладки.
Стоп, у нас ведь нету ни исходного кода, так как Reflector не справился с декомпиляцией, ни отладочной информации?
Все верно, но существует несколько способов отлаживать MSIL-код напрямую. Мне привычнее всего использовать для отладки Visual Studio, поэтому я расскажу именно про этот способ.
Чтобы сгенерировать отладочную информацию, пересобираем библиотеку с ключом /debug: "ilasm.exe pokein.il /dll /debug /out:pokein.dll". В папке с dll файлом появится также отладочный pdb. В тестовом проекте заменяем ссылку с оригинального pokein.dll на новый, и ставим breakpoint'ы прямо в il файле на вызовах get_ActiveClientCount(). Для эмуляции нескольких клиентов просто открываем тестовую страницу в нескольких табах в броузере. При открытии каждого нового таба у нас будет срабатывать breakpoint в одном из методов Bind(). Когда табов станет over 10, мы получим на странице javascript alert с информацией о том, что мы превысили максимальное количество одновременных соединений.
Модификация MSIL
Теперь нам нужно убрать ограничение на 10 одновременных соединений. Открываем il файл и переходим к коду проверки. Первую строчку (в примере — IL_0007) оставляем без изменений. Как мы помним, вызов свойства положит результат в стек, поэтому нам надо его оттуда забрать — заменяем
IL_000c: ldc.i4.s 10
на
IL_000c: pop
Теперь заменяем условный переход
IL_000e: ble IL_0027
на безусловный
IL_000d: br IL_0027
На самом деле, вызов ActiveClientCount можно тоже убрать. Оставляю вам это в качестве домашнего задания.
Повторяем эту операцию во всех местах проверки соединений, собираем il файл обратно утилитой ilasm, обновляем ссылку в тестовом проекте, проверяем — ограничений больше нет, алерты не появляются, задача выполнена.
В бесплатной версии этой библиотеки есть еще некоторые ограничения, от которых можно избавиться тем же способом.
Эта статья написана в образовательных целях, и не является призывом или инструкцией к взлому платных программ.
Надеюсь она вам понравилась, и вы узнали кое-что новое для себя.