- •Модульная архитектура технических средств защиты по от несанкционированного использования
- •Функционирование подсистем и модулей системы защиты по от несанкционированного использования
- •Электронные ключи hasp
- •Глава 1. Методы и средства обратного проектирования.
- •1.1. Понятие обратного проектирования
- •1.2. Основные приемы, используемые злоумышленником при отладке и дизассемблировании программного обеспечения
- •1.2.1. Специфика атак на модули проверки корректности ключевой информации
- •1.2.2. Специфика атак на модули проверки истечения временного срока работы программы или ограничения по количеству ее запусков
- •1.2.3. Отлов злоумышленником вызова WinApi функций при взломе по
- •1.3. Мониторинг событий
- •Глава 2. Методы противодействия обратному проектированию
- •2.1. Методы противодействия отладчикам
- •2.1.1. Защита от отладчиков реального режима
- •2.1.2. Защита от отладчиков защищенного режима
- •2.1.3. Методы, основанные на невозможности полного эмулирования отладчиком среды загрузки программы
- •2.2. Методы противодействия дизассемблированию программного обеспечения
- •2.3. Защита, основанная на человеческом факторе злоумышленника
- •Глава 3. Общие методы защиты программ от отладки и дизассемблирования
- •3.1. Использование недокументированных команд и недокументированных возможностей процессора
- •3.2. Шифрование кода программы
- •Глава 4. Эмуляторы процессоров. Использование эмуляторов для взлома и защиты программного обеспечения.
- •Глава 5. Защита исходных текстов программного обеспечения
- •Глава 6. Идентификация и аутентификация субъектов
- •6.1. Идентификация и аутентификация пользователей с использованием технических устройств
- •6.2. Идентификация и аутентификация с использованием индивидуальных биометрических характеристик пользователя
- •7. Защита от разрушающих программных воздействий
- •7.1. Понятие разрушающего программного воздействия
- •7.2 Модели взаимодействия прикладной программы и рпв
- •7.3 Компьютерные вирусы как класс рпв
- •7.4. Защита от рпв. Изолированная программная среда
- •Глава 8. Руководящие документы России
- •Приложение
- •6.1. Отладка программ в отладчике SoftIce
- •6.2. Дизассемблирование программ с помощью интерактивного дизассемблера Ida Pro
- •6.3. Редактор кода hiew
- •Лабораторные работы
Глава 4. Эмуляторы процессоров. Использование эмуляторов для взлома и защиты программного обеспечения.
Взломщик, получив листинг программы посредством дизассемблирования или в отладчике, видит знакомые инструкции процессора. Скорость взлома защиты во многом зависит от того, насколько он хорошо знаком с данным процессором. Именно против этого факта направлена рассматриваемая защита.
Суть методологии защиты состоит в том, что критичные участки кода программы или вся программа целиком должна быть написана под «самодельный процессор», инструкции которого выполняются эмулятором на реальном процессоре x86. То есть, спроектировать процессор и написать эмулятор под него.
Начинать проектирование процессора следует с определения круга задач, которые ему предстоит решать. Например, если программа зашифрована – то задача – в ее расшифровке. Спроектированный процессор может быть менее эффективен в плане производительности, чем тот, на котором работает эмулятор, однако некритичные по времени, но нуждающиеся в защите процедуры можно переписать под него.
Для затруднения разбора и понимания эмулятора злоумышленником можно придумать много способов.
1. Можно, вместо многих арифметических инструкций ввести одну универсальную, которая будет складывать два специальных регистра, отведенных для сложения, умножать два регистра, отведенных для умножения. После этого, загружать данные в нужные регистры и выполнять инструкции.
2. Код процедур для эмуляции можно зашифровать или сжать, а потом восстанавливать на лету по одной команде самим эмулятором.
3. Эмулировать мультизадачность – несколько ветвей алгоритма выполняются одновременно, что приводит к большой сложности отладки.
При атаке на данную защиту основная задача злоумышленника - разбор и понимание команд эмулятора. Однако, для этого ему придется писать собственный дизассемблер, разбираясь в командах эмулятора без документации, что очень затруднительно.
Следует отметить также, что эмуляторы x86 позволяют обойти очень многие механизмы противодействия отладке, которые используются производителями. В связи с этим, эмуляторы являются мощным оружием двух сторон – злоумышленников и разработчиков систем защиты. Против эмуляторов бесполезны многие противоотладочные приемы, в них широко используется усиление отладочных и отслеживающих механизмов. Эмуляторы позволяют отвязывать ПО от электронных ключей, эмулируя их на программном уровне. Наиболее мощные дизассемблеры (IDA) позволяют подгрузить логику любого виртуального эмулятора, используемого разработчиком.
Для разработчика главная задача – усложнение архитектуры виртуального процессора до такой степени, чтобы его анализ требовал высокой квалификации взломщика и был чрезвычайно трудоемким и утомительным. Наиболее сложным является анализ многопоточных виртуальных машин с динамическим набором команд и множеством циклов выборки и декодирования.
Глава 5. Защита исходных текстов программного обеспечения
Как правило, передача исходных текстов разработанного ПО является обязательным условием заказчика и закрепляется в контракте. Однако, зачастую разработчик не хочет передавать такого рода информацию для того, чтобы защитить используемые алгоритмы, защитить свою интеллектуальную собственность. Открытость исходных текстов программ, вообще говоря, – понятие очень размытое. Очень сложен ответ на вопрос – что более открыто: бинарная программа в 1 килобайт или 1.000.000 строк исходников без адекватной структуры и документации.
Существуют определенные рекомендации, позволяющие, по возможности, скрыть разработчиком исходные коды своих программ от изучения и дальнейшего использования заказчиком. Удалить все комментарии из программы.
Дать всем переменным и функциям бессмысленные имена.После выполнения этих двух условий, в исходном тексте, как правило, не разберется и сам автор, то есть условия договора по передаче исходных текстов выполнены, а текст программы бесполезен.
3. Абстрагирование алгоритма от языка реализации, например, реализация критических для раскрытия компонент на машине Тьюринга, а ее поддержку обеспечить на целевом языке.
Дробление программы. Чем выше степень дробления программы, тем труднее осуществлять анализ ее исходного текста. Если разбить исходный текст программы на элементарные функции, состоящие, например, из 10 строк, то данные функции будут давать очень мало информации о выполняемых ими действиях в общей совокупности. Анализирующему человеку необходимо будет сформировать общую целостную картину работы программы, реконструировать весь алгоритм в целом.
Технология динамического ветвления. Для того, чтобы помешать оформлению целостного понимания исходного кода можно использовать технологию «динамического ветвления» - вычисление адресов перехода программы непосредственно перед передачей управления на функцию, осуществлять передачу управления по указателю, возвращаемого функцией. В данном случае, как правило, статический анализ не позволит построить дерево вызовов. Необходимо будет исследовать программу динамически, что затруднит данный процесс. Если из функции вызываются другие функции, то можно передавать адреса вызываемых функций как аргументы для вызывающих их функции.
Методология контекстной зависимости. В данном случае заводятся специальные флаги – глобальные переменные в пределах одного модуля, а результат работы функций делается зависимым от значений этих флагов. С другой стороны, результаты работы функции отражаются на значении других флагов, используемых в других функциях. Это и определяет методологию контекстной зависимости. В данном случае, работа одной функции становится зависимой от других, вызванных до нее. Анализ работы функции будет многовариантный - необходимо знать, какие функции вызывались до исследуемой, какие значения они возвращали. При реализации данного подхода нужна большая осторожность, малейшая небрежность в реализации приводит к трудноуловимым ошибкам.
Использование ловушек. В данном случае, в текст программы встраиваются «некоторые» ловушки для исследующего его человека, цель которых – направить исследование в неправильное русло. Некоторые из таких ловушек представлены ниже.
Ловушка 1. Данная методология основана на совмещении разнотипных данных в одном аргументе. Допустим, если значение аргумента < n, то он – число, иначе – указатель на функцию. В данном случае необходима тщательная продуманность реализации. Вторым недостатком таких ловушек является то, что они отрицательно сказываются на переносимости программ под другие платформы. Их можно использовать только тогда, когда переносимость не требуется.
Ловушка 2. Использование в программе необычных конструкций. Например, с точки зрения С++, перестановка индекса и имени массива ничего не меняет: buff[666], 666[buff]. Человека же можно поймать на такую запись.
Ловушка 3. Использование пробелов при объявлении макроса. Например
1) Запись Define x(a,b) a+b - Определяет макрос x(a,b) – сумма аргументов.
2) Define x (a,b) a+b – макрос x, заменяющий последовательность (a,b) последовательностью a+b.
При защитах, подобных тем, что представлены в данном разделе, затраты на анализ чужих исходных текстов сравнимы или даже превышают коммерческую ценность заложенных в них алгоритмов. Модификация же этих программ – практически бесполезное занятие: внесенные изменения способны порождать ошибки в непредсказуемых местах и в непредсказуемом количестве.