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

    просто облачко
    Пожалуй, защита ПО всегда была для меня одной из самых любимых тем. Я обожал придумывать сложные хитроумные проверки лицензионности программы, и с упоением реализовывал их. Я всегда держался принципа, что хакер, чтобы взломать защиту, должен изучить максимум технологий использующихся в программе. Пусть думает о синхронизации потоков, если ему захотелось поставить бряк в алгоритме проверки ключа. Пусть изучает вопросы подсчета 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.

    Сейчас сервис запущен в режиме бета версии, и Вы можете тестировать весь функционал абсолютно бесплатно.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 37

      +7
      Вам не кажется, что эта статья больше для «Я пиарюсь» подходит?
        +2
        С одной стороны да, но с другой стороны статья о защите .NET и все предыдущие стати по теме обфускации тоже были опубликованы в этом блоге.
          +3
          А как ваша обфускация влияет на быстродействие? Можно ли обфусцирвать игровые проекты (там, где идёт интенсивная работа с графикой) без потери производительности? Есть ли подводные камни?
            +2
            Подробных тестов по теме производительности мы еще не проводили, но большинство алгоритмов никак не влияют на быстродействие. Единственное исключение — String Encription, этот алгоритм, вероятно, добавит некоторые доп. накладные расходы. Но разница в быстродействии будет очень несущественной и, скорее всего, в реальном приложении её не заметить.

            Кроме того, при необходимости, нужные методы можно исключить из обработки с помощью атрибута ObfuscationAttribute
            0
            Не всякий разработчик готов отправлять свой не обфусцированный код кому попало.
            Вот как вы можете гарантировать что отправленные на защиту проекты не попадут в третьи руки в незащищенном виде?
              +2
              Вопрос безопасности упоминается в статье, в частности мы можем оформить с Вами договор о неразглашении.
                0
                Я считаю что вам необходимо выпустить оффлайновую версию протектора. И на нем раскручиваться.
                А уже заработав некоторую известность переводить сервис в облако.
                NDA в России не пользуется популярностью. Многие даже не знают для чего он и чем он может помочь.
                Самое важное в области защиты ПО — это годами наработанное имя и репутация.
                  +1
                  Офлайн версия, ориентированная на крупных клиентов, есть в наших планах. Но ею мы займемся немного позже, в первую очередь сейчас мы ориентированны на небольшие компании и для них SaaS доступ — возможность существенного сокращения расходов.
                  0
                  [параноик mode on] Но если сборки уйдут через вас, доказать это будет почти не реально для мелкого разработчика. Так что думайте на тему как заработать репутацию. [/параноик mode off]
                    0
                    [параноик mode on]Перед отправкой сборки на наш сервис, добавляйте в нее специальную пометку (класс/строку/атрибут), и если она уйдет через нас, то это легко можно будет отследить ;)[/параноик mode off]

                    А если серьезно, то репутация зарабатывается только долгой безупречной работой и больше никак. Разве что косвенными подтверждениями серьезности намерений могут быть давно зарегистрированное юр. лицо, аттестат продавца от 2009 года, прошлые успешные проекты.
                +3
                Только я по заголовку решил что речь пойдет о проблемах безопасности приложений в Azure?
                  +2
                  А что насчет WCF?
                    +1
                    Как-то не подумал о такой неоднозначности, пожалуй подправлю.
                      +1
                      Куда-то не туда попал, прошлый комментарий — ответ на неоднозначность с облаком Azure.

                      По теме WCF:
                      1. Программа исключает из обфускации типы, переименование которых анализатор считает небезопасным. Я сейчас честно говоря, сходу не вспомню прописывали ли мы конкретно WCF исключения, но многие стандартные базовые классы/атрибуты уже добавлены, и мы постепенно расширяем список исключений
                      2. WCF объекты можно сохранить в отдельной сборке, и вообще не добавлять ее при обфускации, а обфусцировать только тело программы
                      3. Можно исключать из обработки любые отдельные классы с помощью стандартного атрибута ObfuscationAttribute
                    0
                    Renaming — mono.cecil
                      0
                      чертов ctrl+enter макрос.

                      Очень интересно было бы узнать об используемых технологиях. Вот эти я узнал:
                      Renaming, External Method Call Hiding — mono.cecil
                      Assembly Merging — ilmerge

                      а чем вы делаете статический анализ?

                      еще вопрос:
                      Decomposition — что вы делаете с виртуальными методами и делегатами. Ведь вы ломаете
                      a) сигнатуру
                      б) таблицу виртуальных методов
                        0
                        В тексте же написано, что виртуальные методы остаются методами.
                          +1
                          Да, как верно заметил mayorovp, виртуальные методы мы не выносим т.к. одно из главных правил декомпозиции не ломать логику CLR, а с делегатами все ок, от декомпозиции их суть не меняется — просто вместо метода, которому указатель на this передается не явно через стандартный механизм CLR, мы делаем статический метод, которому этот указатель передается явно. Если так можно выразится, то бинарная совместимость в этом случае полная, а логическая связь метода и типа к которому он относился ранее — нарушается.
                            0
                            Получается что для «восстановления» достаточно переместить тело метода обратно? Идентифицировать такие методы будет не так уж и сложно. На такую утилиту уйдет пара часов. По пути можно придавать локальным переменным и классам читабельные имена.

                            Если смотреть на остальные степени защиты, то:
                            External Method Call Hiding
                            тут надо найти вашу табличку ссылок на методы и по довольно редкому опкоду calli вернуть обратно тела функций.

                            остается только String Encryption:
                            который можно сломать в рантайме. воткнув хуки после получения каждой строки типа
                            // строку достали, расшифровали
                            stloc_0 // и сохранили в локальную переменную
                            // волшебная вставка
                            ldloc_0 // расшифрованная строка
                            ldc_i4 100500 // порядковый номер вот такой кодовой вставки
                            call MyHook.SaveDecryptedString // (string value, int stringNum)
                            //

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

                            всё это легко пишется с помощью mono.cecil
                              +1
                              Не существует защиты, которую в принципе невозможно снять, и единственный важный критерий оценки — соотношение стоимости взлома защищенного продукта со стоимостью его приобретения. Соответственно единственное что должна делать защита — делать это соотношение крайне не выгодным для хакера.
                              Если кто-то заявляет что его защита дает 100% гарантии, то значит он врет :)

                              > Получается что для «восстановления» достаточно переместить тело метода обратно
                              Теоретически да, но фактически далеко не всегда возможно определить где был этот метод.

                              > По пути можно придавать локальным переменным и классам читабельные имена.
                              Это не возможно, т.к. процесс обфускации необратим. Максимум можно использовать информацию из окружения (по делегатам, по типам данных и т.п.). Очень многое из этого и так делается в ILSpy (между прочим у него очень умный статический анализатор). Собственно то, насколько это мало помогает, Вы можете видеть сами.

                              External Method Call Hiding — не совсем табличка, опять же можно написать анализатор который по типовым конструкциям пытается найти скрытые методы, там так же используются переменные различные в разных контекстах, но взломщик при очень большом желании сможет написать программу для анализа. Точно так же как мы можем изменив всего пару строчек кода полностью уничтожить все зацепки на которые он рассчитывал (например тот же calli всего лишь один из вараинтов, и взят он лишь по причине своей необычности на сегодняшний день). А с онлайн сервисом такие обновления производить особенно удобно.

                              По String Encryption, в текущий момент времени — соглашусь, способ описанный Вами весьма не плох (кроме сложности покрытия тестами, как правило никогда не удастся извлечь из программы все строки). Но решается это столь же просто — несколько алгоритмов проверки целостности кода, отказ от одной точки шифрования строк, в пользу нескольких (динамически генерируемых и разбрасываемых по отдельным классам) + возможно интеллектуальный алгоритм предотвращения «сдапливания».

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

                              И что еще более важно, сейчас у нас есть большая фора, пока сервис не набрал очень большой популярности, никто не станет писать специализированные анаизаторы под придуманные лично нами алгоритмы. И за это время, мы планируем добавить еще очень много всего вкусного и интересного (в частности небольшую собственную виртуальную машину для самых любопытных хакеру частей кода :)
                                0
                                >Теоретически да, но фактически далеко не всегда возможно определить где был этот метод.
                                Сейчас это очень просто т.к. все прямые вызовы найти довольно легко. Но даже если вы попытаетесь скрыть их через calli или jmp, то это добавит только пару часов в работу по написанию деобфускатора. Причем соотношение будет не в вашу пользу. Вы тратите месяц на создания «не ломающего» алгоритма сокрытия вызова, я трачу день на восстановление оригинального вызова. Причина в том что мне не нужен «работающий» код, мне нужен «оригинальный» код.

                                >Это не возможно, т.к. процесс обфускации необратим
                                Я писал про " читабельные имена", а не «оригинальные имена». Если взломщик хочет «своровать» код, то ему придется потратить время на переименование. Это вполне реализуемо.

                                >External Method Call Hiding
                                >но взломщик при очень большом желании сможет написать программу для анализа
                                «Взломщик» это в первую очередь профессионал. Найти шаблон и обратить алгоритм будет стоить одинаково или дешевле разработки такого алгоритма(выше и ниже написано почему). Причем ваши «изменения» сервиса никак не защитят взламываемое или воруемое приложение. Его уже скачали и ломают. С каждым вашим релизом взломщик будет посылать вам своё мега-приложение-болванку на обфускацию и получать свежие алгоритмы. Может даже нейросеть прикрутит :)

                                >Насчет того, что все это легко пишется — очень сильно сомневаюсь, на разработку сервиса у нас ушло около года.
                                Сочувствую, сам написал раньше «мега-защиты» которые ломали за день.
                                Взлом делается быстрее защиты, за счет того что надо получить читабельный, похожий на оригинал код для дальнейшего анализа. Причем «запускаемость» кода часто не нужна.
                                >и при этом обратный процесс восстановления значительно более сложная процедура (намного проще имея полную информацию уничтожать её, чем имея лишь остатки данных восстанавливать логические связи).
                                Но вы же её не уничтожаете(кроме имен). Только размазываете тонким слоем, теряя производительность, портируемость и другие качества проекта.
                                  –1
                                  Вот потому OpenSource смотрит на всяческие системы защиты кода и копирайта как на… детей :)
                                    +1
                                    На словах все очень просто, а Вы бы попробовали ;)

                                    > мне нужен «оригинальный» код.
                                    Оригинального кода уже нет, взломщику точно так же нужно строить все связи и искать сложные зависимости для того чтобы внести изменения и не сломать работу программы. Допустим есть классы a, b и их интерфейс IBase. Если в одном из них переименовать метод а в другом — нет, то программа просто вылетит при загрузки этого типа данных. Аналогично и с рефлекшином, только теперь имена бессмысленны и скрыты под String Encryption. И как и нам хакеру придется выявлять атрибуты содержащие в себе строковые имена.

                                    > Только размазываете тонким слоем, теряя производительность, портируемость и другие качества проекта.
                                    А можно конкретнее, в чем потеря портируемости и особенно производительности? Cтатические функции медленнее чем методы экземпляров или короткие имена вида a,b,c работают хуже чем оригинальные?

                                    > Причем «запускаемость» кода часто не нужна.
                                    Если цель только посмотреть один маленький кусочек исходного кода — то это ошибка не обфускатора, а разработчика лицензионных ограничений. Правильная защита строиться по другому, и никакой обфускатор здесь не поможет. Для того чтобы защиту трудно было снять, она должна быть очень плотно интегрирована в программу, и проверки лицензии должны быть во множестве мест программы. А как самый идеальный случай, для особенно надежной защиты, я бы порекомендовал использовать ключи с собственным процессором для защищенного выполнения кода внутри них. В такой ключ можно вынести несколько реальных алгоритмов из программы и этим усложнить обход защиты на несколько порядков.
                                      0
                                      >На словах все очень просто, а Вы бы попробовали ;)
                                      А я это не только пробую.
                                      >Оригинального кода уже нет, взломщику точно так же нужно строить все связи и искать сложные зависимости для того чтобы внести изменения и не сломать работу программы.
                                      Вы защищаете от «кражи исходников» и «взлома защиты». Для первого варианта нужно восстановить название файлов, места вызовов и строки. Как это сделать я описывал выше. Остается кропотливая работа человека по анализу кода и переименованию. Этим обычно не занимаются, а ломают защиту, меняют логотип и продают как свою. Тут мы приходим ко второму виду взлома. Где «Оригинального кода уже нет, взломщику точно так же нужно строить все связи и искать сложные зависимости для того чтобы внести изменения и не сломать работу программы» делать не надо, надо только получить код похожий на оригинал для анализа. Как обернуть ваши способы защиты я писал выше.
                                      > Допустим есть классы a, b и их интерфейс IBase. Если в одном из них переименовать метод а в другом — нет, то программа просто вылетит при загрузки этого типа данных.
                                      К сожалению вы неправы. Имена классов/членов класса не используются, используются только токены метаданных, и собственно если «переименовать» класс в метаданных, то он «переименуется» везде. Учитывая что вы сливаете все сборки в одну, вы облегчаете задачу обратного переименования, ведь меж сборочного биндинга нет.

                                      >Аналогично и с рефлекшином, только теперь имена бессмысленны и скрыты под String Encryption. И как и нам хакеру придется выявлять атрибуты содержащие в себе строковые имена.
                                      Как украсть ваши строки я уже писал. Если бы я видел сам алгоритм или пример его встраивания, я бы выдал еще более интересные варианты взлома. Шифрование строк и упаковка кода должны «возбуждать» только очень неопытных программистов. Если проект тяжело сидит на рефлекшене то взломщику придётся разбирать что и куда идёт. Но это «заслуга» не вашего обфускатора, и без него, даже с исходниками такой код сложно анализировать.

                                      >А можно конкретнее, в чем потеря портируемости и особенно производительности? Cтатические функции медленнее чем методы экземпляров или короткие имена вида a,b,c работают хуже чем оригинальные?
                                      Портируемость:
                                      Как ведет себя обфускатор с Medium Trust кодом? Ведь некоторые опкоды и их сочетания являются unverifiable(calli к примеру). Это windows azure, sharepoint, silverlight, unity3D, windows phone, clickOnce web приложений.
                                      Часть опкодов не поддерживается Mono разных версий.
                                      Производительность:
                                      Про имена я сказал выше. Они к осполнению кода отношения не имеют и участвуют в биндинге.
                                      IL Оптимизатор ничего не знает о calli, в итоге вы эффективно мешаете оптимизатору инлайнить методы. Об оптимизации хвостовой рекурсии можно вообще забыть. Помимо того что вы «раздуваете» стек и создаете «неявные» точки в потоке исполнения в которых могут появиться «асинхронные» исключения(ThreadAbortException). Еще неизвестно проверяете ли вы CER аттрибуты и не нарушаете ли контракты надежности.

                                      Причем это то что я видел в ваших примерах. Я представляю насколько всё печальнее на самом деле.

                                      >я бы порекомендовал использовать ключи с собственным процессором для защищенного выполнения кода внутри них
                                      Именно, обфускация бесполезная трата денег.
                                        0
                                        >восстановить название файлов, места вызовов и строки.
                                        Опечатался.
                                        восстановить названия типов, места вызовов и строки.

                                        Возникла мысль. Вы дебаг символы надеюсь вытираете? Mono.Cecil их старается сохранить, было бы приятно их обнаружить.
                                          0
                                          > Этим обычно не занимаются, а ломают защиту, меняют логотип и продают как свою
                                          Чтобы сменить лого, совсем не обязательно лезть в код, достаточно открыть ресурсы. А вот чтобы снять защиту, особенно когда она хорошо распределена по программе и программа при этом обфусцированна, нужно очень много сил и времени, а главное после выпуска новой версии, все придется повторять вновь, что делает такой «взлом» абсолютно нерентабельным.

                                          > К сожалению вы неправы. Имена классов/членов класса не используются, используются только токены метаданных
                                          Это не так, токен каждого метода храниться отдельно и если не учитывать связи между типами, то программа работать не будет :) Можно конечно все методы «a» переименовать разом в одно имя, а все методы «b» в другое, но учитывая что таких методов «a» несколько сотен, они все разные и никак друг с другом не связаны, это очень вряд ли хоть чуть-чуть поможет с читаемостью кода.

                                          > IL Оптимизатор ничего не знает о calli, в итоге вы эффективно мешаете оптимизатору инлайнить методы
                                          Суть External Method Call Hiding как раз в том, что скрываются вызовы только _внешних_ методов из других сборок. Вызовы методов внутри сборки остаются нетронутыми. А касательно inline, Вы сильно переоцениваете оптимизатор, как правило он может заинлайнить внешние вызовы только с атрибутом TargetedPatchingOptOut (только в случае NGen), MethodImplAttribute (FW 4.5) и подобными. С уверенностью скажу что никаких «неявных» точек в стеке не появляется и «асинхронные» эксепшены не происходят. Если бы это было не так, из среды .NET не возможно было бы обращаться к неуправляемому коду, а это не так, более того, множество методов внутри самой CLR заканчиваются неуправляемым кодом.

                                          > Если проект тяжело сидит на рефлекшене то взломщику придётся разбирать что и куда идёт
                                          Намного интереснее это выглядит после нашего обфускатора, когда вместо какого-нибудь type.GetMethod(«GetPrice») увидит:
                                          1. calli по которому еще надо догадаться, что это был вызов GetMethod
                                          2. Вызов какого-нибудь «d(int, int)» по которому нужно догадаться что это String Encription
                                          3. Расковыряв всю эту цепочку пользователь получит строку, пусть это будет «a» (скорее всего примерно так и будет) и по нему надо каким-то волшебным образом восстановить, что это бывший «GetPrice»
                                          И так почти на каждой строчке.

                                          > Возникла мысль. Вы дебаг символы надеюсь вытираете? Mono.Cecil их старается сохранить, было бы приятно их обнаружить.
                                          Нет, конечно мы их не сохраняем, они там и не могут оказаться, т.к. как я говорил чуть раньше, мы не правим старую сборку а создаем с нуля полностью новую.

                                          > Именно, обфускация бесполезная трата денег.
                                          Как раз наоборот, покупать аппаратные ключи и встраивать их в необфусцированную .NET программу — столь же глупо как и пытаться добавить защиту хардверными ключами в Open Source приложение выложенное на github (разницы фактически никакой). Только комплексная защита может дать желаемый эффект.
                                +1
                                По поводу технологий — в основе ядра нашего обфускатора лежит пропатченный и доработанный нами mono.cecil и поверх него строится вся логика дерева разбора, перименования, линковки библиотек и т.д.

                                Никакие другие технологии типа того же ilmerge мы не используем. Более того, мы не производим никаких изменений в пришедшей на вход сборке, а на основе механизмов cecil создаем полностью новую.
                              0
                              Выглядит опасно. Интересно как при таком тяжелом рефакторинге дела с совместимостью. Как разруливается явная и неявная реализация интерфейсов? Всё считается виртуальным? Как обфусцируются делегаты, с оглядкой на граф ссылок? Что со статическими методами и конструкторами? Что со строками, содержащими имена из метаданных (типа имен свойств в реализации INotifyPropertyChanged или атрибутов вроде ContentProperty)?
                              Скорее всего, код который работает с рефлексией и его логика построена на захардкоженном знании о структуре кода полетит. Например, всякие системы плагинов, MEF-ориентированные сборки и свои Dependency Injection велосипеды.
                              Пробовали отлаживать на сложных расширяемых приложениях?
                                +1
                                Разницы между явной и неявной реализацией интерфейсов для обфускатора нет, т.к. и те и другие всегда будут виртуальными функциями, которые не попадают под декомпозицию. А renamer умеет строить умные деревья зависимостей чтобы дать правильные имена. Про делегаты уже писал выше, конструкторы остаются на месте, статические методы тем более прекрасно декомпозитятся.

                                По поводу имен которые идут текстом в коде и в атрибутах — одна из самых сложных тем, у нас целый ряд анализаторов отвечает за прописывание исключений и обновление имен (анализатор атрибутов, анализато WPF, анализатор Reflection обращений). Но все равно, в сложных случаях, они могут не справиться и тогда спасает их явное исключение через ObfuscationAttribute.

                                > Например, всякие системы плагинов, MEF-ориентированные сборки и свои Dependency Injection велосипеды.
                                Если писать их правильно, то все будет работать. Я лично, очень рекомендую использовать Reflection вызовы по пользовательским атрибутам, а не по жестко забитым в коде именам, а так же проверять типы через typeof а не сравнением строк. Ряд достаточно простых правил, позволяет писать Reflection код, хорошо совместимый с любым умным обфускатором.

                                > Пробовали отлаживать на сложных расширяемых приложениях?
                                Да, тестирование и разрешение всяких сложных случаев растянулось у нас больше чем на 5 месяцев, поэтому с одной стороны могу с уверенностью сказать что многие сложные системы заработают без малейшего изменения кода. С другой стороны — точно есть случаи в которых потребуется вмешательство программиста.
                                +2
                                Еще интересный вопрос. Как ведет себя обфускатор с Medium Trust кодом? Ведь некоторые опкоды и их сочетания являются unverifiable(calli к примеру).
                                  0
                                  Вопрос очень актуален для сайтов, windows azure приложения, sharepoint приложений, silverlight приложений, unity3D приложений, windows phone приложений.
                                  0
                                  Лучшая защита приложения это разумная цена и своевременный выпуск релизов.
                                    +1
                                    Абсолютно согласен защита должна быть комплексной от технических мер до административных.
                                    0
                                    Ему про Кузьму, а он – про Ерему.
                                      +1
                                      Ребята — респект! За Вами вменяемая ценовая политика и работоспособная Free — версия.
                                        0
                                        Есть интересная идея: off-line — за деньги, online — бесплатно.
                                          0
                                          Спасибо, мы будем стараться.

                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                        Самое читаемое