Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
PASOIB.doc
Скачиваний:
119
Добавлен:
17.09.2019
Размер:
4.95 Mб
Скачать

Глава 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.

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]