Как стать автором
Поиск
Написать публикацию
Обновить

Облачная защита для .NET приложений

Время на прочтение6 мин
Количество просмотров4.1K
просто облачко
Пожалуй, защита ПО всегда была для меня одной из самых любимых тем. Я обожал придумывать сложные хитроумные проверки лицензионности программы, и с упоением реализовывал их. Я всегда держался принципа, что хакер, чтобы взломать защиту, должен изучить максимум технологий использующихся в программе. Пусть думает о синхронизации потоков, если ему захотелось поставить бряк в алгоритме проверки ключа. Пусть изучает вопросы подсчета COM ссылок, если он хочет вмешаться в мой алгоритм. Пусть думает о том, как представлены битовые карты изображений в памяти, если он решил разобраться, как я сохранил данные ключа.

Да, C++ был почти идеальным языком в этом плане. Но времена меняются, старые технологии уходят и на их место приходят новые более продуктивные и удобные. Так наша команда перешла на .NET. Но в обмен на простоту разработки и удобство отладки, мы в придачу получили в довесок и простоту декомпиляции нашего ПО. Теперь хакер мог не просто обойти лицензионные ограничения, но и получить почти полный исходник нашей программы просто скормив ее рефлектору.
Разумеется, в качестве решения этой проблемы на рынке было представлено множество различных обфускаторов. Но, как ни странно, большинство из них разочаровывали меня сразу с двух сторон: и ценовой политикой (даже минимальная лицензия некоторых превосходила стоимость нашего ПО в несколько раз), и «интеллектуальностью» алгоритма. Так, после некоторых обфускаторов, умудрялись падать даже простые WinForms приложения. Что же касалось WPF, то без долгого-долгого черного шаманства над эксклудами, запустить среднего размера программу не представлялось возможным в принципе.

Так сформировалось понимание проблемы и четкое желание создать свой продукт, сводящий озвученные выше проблемы к минимуму. И появился SaaS обфускатор и протектор .NET кода AppFuscator.com

Обфускатор и протектор .NET кода appfuscator




Алгоритмы защиты


Renaming

Обфускация классов и их членов, с полной поддержкой Generics, наследования, перегрузки виртуальных методов, стандартных атрибутов обфускации.
Доступны различные варианты именования: английскими буквами, английскими буквами с перегрузкой по типу параметров, непечатаемыми символами и ряд других.

Assembly Merging

Объединение нескольких исходных защищаемых сборок в одну конечную, с целью усложнения анализа и декомпиляции.
В текущей версии в качестве встраиваемых сборок должны выступать сборки, не содержащие WPF ресурсов.

Decomposition

Декомпозиция структуры классов в процедурное представление — наша собственная оригинальная разработка, базирующаяся на идее перевода программы из объектно-ориентированной формы (простой для реверс-инжиниринга) к процедурному стилю, с максимальным уничтожением всей доступной информации хранимой в метаданных (но сохранением полной работоспособности сборщика мусора).
Расскажу чуть подробнее. Допустим, у нас есть сборка с такой структурой классов:

Обфускатор кода

После выполнения декомпозиции мы увидим следующее:
.NET обфускатор

Метод, который выделен на скриншоте — это и есть бывший MainForm_Load — обработчик загрузки формы. Только теперь он, как и весь остальной код, лежит за пределами класса, к которому относится, в глобальном пространстве имен (в отличие от C#, где любой метод должен относиться к классу, в IL допустимо объявление обычных глобальных функций).

В самой форме (теперь это класс b) остался только один метод: Dispose. Он является перегрузкой виртуальной функции, поэтому мы его не выносим.

Как видите, сложность чтения повышается в разы, и взломщику очень сложно будет разобраться, какие методу к чему относились ранее. При этом классы превращаются в пустые обертки, содержащие только поля данных (с потерянными типами) и остаток виртуальных функций.

External Method Call Hiding

Сокрытие вызова внешних методов — подмена явного вызова методов из внешних сборок (в том числе обращений к Common Language Runtime), на неявное обращение по неуправляемому указателю.
Небольшой пример. Было:

public void ShowMessage(string text)
{
    MessageBox.Show(text);
}


Стало:
// <Module>
public static void a(object obj, string text)
{
    object arg_0C_0 = calli(System.Int32(System.String), text, g.b);
}


String Encryption

Шифрование строк на основе собственного алгоритма. Для категорического усложнения жизни потенциальным разработчикам автоматизированного декодера, в защищаемой программе формируются динамические переменные, зависимые от контекста.

Reflection Analyzing

Анализ обращений к механизму отражения — набор алгоритмов, отслеживающих обращение к Reflection.
Мне всегда категорически не нравилось, что после сборки очередной версии программы начинается следующий этап – танцы с бубном вокруг обфускатора. Поэтому в нашем продукте предусмотрен анализатор, который обучен автоматически отслеживать связи, и корректировать имена в коде программы. Он имеет довольно мощную логику разбора сложных конструкций и выбора конечного решения. Все возможные случаи закрыть автоматически он, конечно, не сможет, но жизнь разработчику облегчит существенно.
Пусть у нас есть два класса:

class ClassA
{
    string GetText() { return "A"; }
    public int smallField;
}

class ClassB
{
    string GetText() { return "B"; }
}


Рассмотрим следующий пример кода:

public void HabraTestFirst(int x)
{
    Type work = null;
    string method = "gettext";

    if (x == 0)
        work = typeof(ClassA); // Берем ClassA
    else
    {
        string name = "HabraCode.ClassB, HabraCode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
        work = Type.GetType(name, true); // Берем ClassB
    }

    // И вызываем у него метод GetText
    HabraReflectionCall(work, method);
}

public void HabraReflectionCall(Type target, string method)
{
    var call = target.GetMethod(method, BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Instance);
    var obj = Activator.CreateInstance(target);
    call.Invoke(obj, null);
    MessageBox.Show(string.Format("HabraReflection call: {0}.{1}", obj.ToString(), call.Name));
}


В этом примере, в зависимости от переданного на вход числового параметра, будет вызван метод либо в классе ClassA либо в ClassB. При этом никакой связи наследованием\интерфейсами эти классы между собой не имеют.

Компилируем простую программу:
var reflector = new Reflector();
reflector.HabraTestFirst(0);
reflector.HabraTestFirst(1);


Запускаем и вуаля:
Обфускация .NET Reflection

Как видите, оба класса и оба метода в ходе обфускации были переименованы, но программа смогла выявить между ними зависимость, и обновила ссылку на имя в Reflection вызове.
Еще более интересный пример, в котором мы не только обращаемся через Reflection, но еще и находим нужное поле через перечисление:

public void HabraTestSecond()
{
    FieldInfo result = null;
    var anyobj = new ClassA().GetType();

    foreach (var it in anyobj.GetFields())
    {
        if (it.Name == "smallField") // Ищем у класса поле smallField перебирая все по очереди
            result = it;
    }

    if (result == null) throw new InvalidOperationException();
    MessageBox.Show("HabraReflection field: " + result.ToString());
}


При запуске программа честно сообщит нам:
Reflection Alnalyzing module

Как это работает? Все просто — увидев характерную конструкцию – перечисление полей, полученных из Reflection, анализатор смог адаптироваться и обновить запрашиваемое имя в IL коде.
Разумеется, такой подход будет работать не всегда, если конструкция будет более многошаговой или имя искомого метода будет браться, к примеру, из внешнего файла, то наш интеллигентный анализатор честно признает свое поражение.

Исходный код можно скачать здесь.

WPF Analyzing

Автоматическое исключение из обфускации типов, методов и полей, к которым имеются обращения из Windows Presentation Foundation. Программа производит декомпиляцию и анализ скомпилированных XAML ресурсов в сборках. Полностью поддерживает расширения синтаксиса WPF, включая сложные конструкции (например, PropertyPath и другие).
Благодаря этому, в программе, написанной на WPF, переименовано будет только то, что должно быть переименовано.

Типичный пример программы после обфускации:
Результат обфускации .NET приложения
(кликните для увеличения)

Почему SaaS?



Все просто — вместо того, чтобы покупать хороший коробочный обфускатор за несколько тысяч долларов, а затем постоянно платить за покупку его обновлений (ведь технологии платформы .NET развиваются очень быстро), Вы приобретаете доступ к сервису онлайн обфускации. И после этого платите только за тот объем работы, который нужен лично Вам. Выпускаете версию раз в месяц – платите только за это.
Ценовая политика сейчас в стадии формирования, но я с уверенностью могу сказать о том, что условия будут вкусными. Кроме того, будет доступна бесплатная версия, функционал которой превосходит все бесплатные обфускаторы, представленные на данный момент.

Это безопасно?


Мы очень серьезно подходим к вопросу защиты Ваших данных.

Первое и самое главное: Вам не нужно отправлять на сервер исходные коды программ. Вы присылаете только уже скомпилированные сборки, именно в таком виде, как их увидели бы Ваши пользователи (а возможно и не только пользователи), если бы Вы не занимались вопросом защиты и не обфусцировали их. Никакой другой информации не потребуется.
Весь процесс обфускации производится на выделенных серверах, доступ к которым имеет только несколько человек из нашей команды. Разумеется, мы используем последние версии ПО и производим регулярные апдейты. Кроме того, модуль обфускации и web-фронтенд для взаимодействия с пользователем, физически размещены на отдельных серверах, что повышает защищенность и масштабируемость системы.

Мы являемся юридическим лицом, и готовы предоставить все необходимые документы, такие как договор на использование нашего сервиса и NDA.

Сейчас сервис запущен в режиме бета версии, и Вы можете тестировать весь функционал абсолютно бесплатно.
Теги:
Хабы:
Всего голосов 50: ↑39 и ↓11+28
Комментарии37

Публикации

Ближайшие события