Эволюция систем защиты на электронных ключах

    Эта статья посвящена развитию систем защиты на аппаратных ключах, видам атак, с которыми пришлось столкнуться за последние годы, и тому, как им удалось противостоять. Рассмотрены возможности электронных ключей, которые напрямую влияют на степень защиты программного обеспечения, и основные проблемы, присущие данной технологии. Автор статьи является ведущим разработчиком проекта Guardant, компания «Актив».

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

    Рассмотрим защиту Windows-приложений, разработанных с использованием компилируемых языков программирования (C, C++, Pascal, Delphi, Fortran и т.д.).

    Обмен данными между программой и электронным ключом


    Основным способом построения надёжной защиты является использование библиотеки API для работы с электронным ключом. Как правило, API поставляется в виде статической и динамической библиотеки.

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

    Программа обменивается данными с электронным ключом через библиотеку API, которая напрямую взаимодействует с драйвером электронного ключа. Типовая схема обмена между защищённой программой и электронным ключом изображена на рис.1.

    image

    Атаки в такой схеме нацелены на взаимодействие между различными модулями защиты. Перехват запросов к электронному ключу на уровне драйвера электронного ключа (1) или драйвера USB-шины (2) не требует повторной модификации каждой новой версии приложения, в отличие от варианта с перехватом вызовов статической библиотеки API (3).

    Атака на драйвер электронного ключа


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

    Переходя к частностям, хотелось бы остановиться подробнее на защите от программных эмуляторов в электронных ключах Guardant. Драйверы электронных ключей Guardant содержат электронную подпись (ЭП). При вызове функций Guardant API защищенное приложение автоматически проверяет подпись драйвера в оперативной памяти. Поскольку закрытый ключ не известен, создать драйвер-эмулятор с правильной подписью невозможно. Убрать проверку мешает виртуальная машина (псевдокод), с помощью которой защищены исполняемые файлы драйверов и библиотеки Guardant API. Схема проверки изображена на рис.2.

    image

    После внедрения такой защиты на практике, программные эмуляторы сместились на уровень USB-шины (2-й вариант атаки).

    Атака на драйвер USB-шины


    Создание такого эмулятора потребовало изучение протокола обмена между драйвером электронного ключа и драйвером USB-шины. Как это ни парадоксально звучит, но в такой ситуации более надёжными оказались LPT-ключи, т.к. драйвер электронного ключа напрямую взаимодействует с LPT-ключом через порты ввода/вывода компьютера, минуя промежуточный драйвер.

    К сожалению, полностью избавиться от программных эмуляторов на уровне USB-шины, используя ключи с симметричной криптографией, невозможно. Тем не менее, хорошая защита, построенная на постоянном обмене с электронным ключом, может потребовать не один день для записи всех возможных посылок и ответов к ключу и сработать у нелегального пользователя в самый неподходящий момент. Взломанные программы, перестающие работать по непонятным причинам, лишь тому подтверждение.

    Отдельно хочется упомянуть о защитах, когда разработчики ограничиваются простой проверкой наличия электронного ключа. Это грубая ошибка. Используя дизассемблер, “независимость” такой программе можно подарить за 15 минут.

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

    Атака на перехват вызовов статической библиотеки API


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

    С помощью современного дизассемблера можно быстро распознать функции API в программе. А раз так, то все вызовы функций легко перехватить. Это означает, что коды доступа, запросы и ответы по-прежнему остаются уязвимы. И если сам разработчик программы не защитил вызовы функций API, то это наилучшее место для атаки.

    Для исключения возможности перехвата вызовов статической библиотеки API в защищённой программе, необходимо ключевые функции приложения и функции API объединить в единое целое. Только тогда анализировать параметры, перехватывать вызовы или модифицировать запросы и ответы к функциям API будет действительно сложно. На практике разработкой защиты начинают заниматься уже после того как написан основной код приложения. Очень часто на глубокую интеграцию взаимодействия программы и электронных ключей не хватает времени, а возможно, и желания. Наименее трудоёмкий способ повысить качество защиты, это дополнительно использовать программные средства, усложняющие анализ кода. В этом случае, взаимодействие функций программы и функций статической библиотеки API становится трудным для понимания.

    Возвращаясь к электронным ключам Guardant, скажем, что все библиотеки Guardant API защищены от анализа и модификации с помощью виртуальной машины. Под виртуальной машиной подразумевается псевдокод, полученный из оригинального бинарного кода программы, и соответствующий ему интерпретатор. Инструкции псевдокода могут быть выполнены только на том интерпретаторе, для которого он был сгенерирован. Интерпретатор отвечает за защиту инструкций псевдокода и самого себя от модификации при помощи множественного контроля целостности. Все параметры инструкций, константы, адреса переходов расшифровываются на хэшах фрагментов псевдокода и самого интерпретатора. Для затруднения анализа интерпретатор псевдокода защищён с помощью полиморфной обфускации. Перечисленные характеристики реализуются уникальным образом в каждой копии виртуальной машины.

    Технология защиты псевдокодом доступна всем желающим с помощью сервиса Guardant Armor. У такого подхода есть ряд преимуществ: инструмент защиты постоянно обновляется и недоступен для изучения. При этом особую выгоду получают разработчики, использующие электронные ключи Guardant. Сервис позволяет защищать функции программы одновременно с функциями статической библиотеки Guardant API (технология Guardant Monolith). Наличие библиотеки Guardant API внутри приложения определяется автоматически, поэтому никаких дополнительных перекомпиляций приложения не требуется. В результате, при каждой защите приложения создаётся уникальная копия виртуальной машины со своими инструкциями, константами, обфускацией, в которой логика работы программы тесно связана с библиотекой электронного ключа. Теперь для перехвата вызовов статической библиотеки или атаки на саму библиотеку придётся разбираться с каждой защитой индивидуально.

    image

    Рассмотрим это на примере небольшого тестового приложения, фрагмент которого приведён на рис.4. Данный пример очень ярко характеризует уязвимость вызовов любой статической библиотеки внутри приложения. Проблема касается всех производителей электронных ключей.

    image

    Предположим, что функция приложения MyLogicAndVerifyDongle содержит некоторые программные вычисления с использованием электронного ключа. Работа без данной функции невозможна, т.к. она содержит часть ключевой логики приложения. При этом вызов функции осуществляется из менее важного участка кода программы. Для обращения к электронному ключу используются вызовы статической библиотеки Guardant API. В данном примере это вызовы функций GrdRead и GrdCrypt. В начале каждой функции находится лишь переход в защищённую область VM_Start. Тем не менее, сама функция MyLogicAndVerifyDongle остаётся незащищённой и может быть подвержена атаке.

    Теперь проведём защиту функций API и ключевых функций приложения с помощью сервиса Guardant Online. Фрагмент защищённого приложения приведён на рис. 5.

    image

    После защиты функция MyLogicAndVerifyDongle содержит лишь переход в защищённую область Guardant_VirtualMachine. По адресам, где ранее располагался исполняемый код функции, оказываются мусорные инструкции. Сама функция транслируется в псевдокод и исполняется на той же самой виртуальной машине, что и функции Guardant API. Больше нет возможности ставить точки останова на вызовы функций API, т.к. переходы спрятаны внутри виртуальной машины. Это означает, что для взлома программы придётся раскручивать всю логику работы виртуальной машины, а это на порядок сложнее, чем простой перехват функций API.

    Выводы


    Ряд рекомендаций для построения надёжной защиты.

    1. Необходимо использовать статические библиотеки API в программе. Вызовы библиотеки API должны быть тесно интегрированы с логикой защищаемой программы – это гарантия создания стойкой защиты.
    2. Лучше использовать ключи с асимметричной криптографией, т.к. для них не существует простого способа создания табличных эмуляторов.
    3. Код приложения и статическую библиотеку API необходимо защитить от анализа с помощью программных средств защиты, где отсутствует простая возможность перехвата вызовов функций API в программе. Для разработчиков, использующих технологии Guardant, идеальным решением будет Guardant Monolith.
    «Актив» 60,74
    Компания
    Поделиться публикацией
    Похожие публикации
    Комментарии 14
    • 0
      Ну вот что это за ерунда? Это первый пост компании на хабре?
      ИМХО не совсем верный способ привлечь аудиторию — слишком сухо и абстрактно.

      Есть же конкретный шикарный продукт Guardant Code. Напишите про то, как можно защитить таким ключом обычное приложение — вот это будет лучшая вводная в технологии актива.
      • 0
        Я думаю, такая статья появится. А это, так сказать, общее введение.
        • +1
          Спасибо за коммент!

          Мы данной статьей хотели в принципе показать слабые места разных электронных ключей, тут действительно Guardant Code стоит особняком и позволяет делать весьма интересную защиту. Обязательно про него напишем в следующий раз.
          • 0
            Жду с нетерпением :)
          • +1
            Наоборот, компания, в отличие от всяких интел, майкрософт и HP не занимается копипастой маркетинговых буклетов для умственно отсталых лиц, принимающих решения, а пишет на Хабре про технические подробности. Пожалуйста, не слушайте Bobos и продолжайте в том же духе.

            А вы, уважаемый хабраюзер, если не понимаете, что такое mov eax, dword_6dfb4c, что забыли на Хабре?

            А так, непонятно, как сделан этот момент:

            > При вызове функций Guardant API защищенное приложение автоматически проверяет подпись драйвера в оперативной памяти. Поскольку закрытый ключ не известен, создать драйвер-эмулятор с правильной подписью невозможно.

            Что мешает взять существующий драйвер, и посмотреть какая у него подпись, и выдавать ту же подпись драйвером-эмулятором? Ведь программа не может прочесть область памяти, в которой лежит драйвер, и проверить, что он настоящий? Или я что-то не понял?

            А также, вопрос, будут ли статьи с разбором недостатков технологий-конкурентов, если они конечно у них есть?
            • 0
              Guardant API может (и читает) область памяти с загруженным туда драйвером, и проверяет подпись, так сказать, по полной программе.

              Касательно конкурентов: недостатки есть у всех, у нас в том числе. Но мы не считаем корректным упирать не недостатки конкурентов — гораздо интереснее опираться на достоинства собственной продукции, хотя при этом сравнение с конкурентами в какой то степени подразумевается.

          • 0
            +100500
            • 0
              Перехватив IoCallDriver мы будем контролировать irp пакеты передаваемые драйверу приложением. Тем самым проанализировать и отвязать защиту
              • +1
                Для прошлых поколений ключей это вполне актуальный комментарий. И там сложность отвязывания защиты упиралась именно в сложность анализа трафика между драйвером и приложением. К слову сказать, и на Stealth II делались защиты которые не ломались годами! Если достойно пользоваться возможностями ключа (шифрование, хеширование,...) и завязать на них логику приложения, а также сделать нетривиальные зависимости от условий анализа, даты, времени, и прочего — то на сбор информации для эмуляции ключа может уйти уйма времени, причем без гарантий что эмулятор не даст сбой через месяц только потому, что «с 25 по 28 число каждого месяца» защита работает совершенно по другому :)

                Для новых ключей садиться на драйвер бессмысленно — они сделаны на мощном микропроцессоре который позволяет сквозным образом шифровать трафик между ключом и приложением. Шифрование производится на сеансовых 15-минутных ключах алгоритмом AES. Этот трафик анализировать бессмысленно. И в статье описано что при этом нужно ломать и как защититься.
                • 0
                  Немного поправлюсь. Для старых поколений ключей Stealth 2 и Stealth 3 простой перехват Irp пакетов между приложением и драйвером ничего не даст. Для создания эмулятора потребуется реверсировать Guardant API и драйвер, которые защищены нашим псевдокодом.

                  Эмулировать на уровне драйвера USB-шины, конечно, заметно проще — собственно о том, в том числе, и статья.
                  • 0
                    виртуальная машина работает и на нулевом кольце?
                    • 0
                      Именно так!
                      • 0
                        это действительно усложняет отвязку
              • 0
                Сдаётся мне, что если защита станет массовой, то вскоре после этого появятся скрипты для олли для её снятия.

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

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