Автор: Пользователь скрыл имя, 23 Марта 2012 в 03:04, дипломная работа
Актуальность работы. Многие направления науки и техники, имеющие отношение к получению, обработке, хранению и передаче информации, в значительной степени ориентируются на развитие современных компьютерных систем (КС) [30]. Такие системы представляют разнообразную и весьма сложную совокупность вычислительных устройств, систем обработки информации, телекоммуникационных технологий, программного обеспечения и высокоэффективных средств его проектирования и в общем случае представляющие гетерогенную программно-аппаратную среду.
Введение 4
Глава 1. Анализ методов защиты программных средств 11
1.1 Методы защиты информации с помощью аппаратных средств 12
1.2 Программные средства защиты информации 16
1.3 Анализ программных средств как объекта защиты 21
1.4 Анализ структуры программных систем защиты информации 24
1.5 Выводы 26
Глава 2. Построение методов защиты программных средств с помощью,
запутывающих преобразований 28
2.1 Понятие запутывающих преобразований для реализации защиты
программных средств вне доверенной вычислительной среды 29
2.2 Классификация запутывающих преобразований 32
2.2.1 Преобразования форматирования 32
2.2.2 Преобразования структур данных 33
2.2.3 Преобразования потока управления .34
2.3 Классификация методов анализа программ .44
2.3.1 Методы статического анализа .45
2.3.2 Методы статистического и динамического анализа 47
2.4 Классификация способов запутывания к применяемым методам анализа и распутывания программ 48
2.5 Оценка эффективности применения запутывающих преобразований 50
2.6 Выводы .51
ГлаваЗ. Построение метода защиты программных средств с помощью
запутывающих преобразований ;.53
3.1 Построение графа потока управления 56
з
3.2 Преобразование графа потока управления 60
3.5 Теоретическое обоснование устойчивости метода 68
3.6 Практическое обоснование устойчивости мето да 71
3.7 Выводы 72
Глава 4. Решение практических задач защиты программных средств 74
4.1 Анализ характеристик методов защиты программных средств 74
4.2 Выбор объектов тестирования 74
4.3 Методика оценки эффективности защиты 75
4.3.1 Оценка эффективности программных средств 80
4.4 Оценка устойчивости метода к ручному анализу и дизассемблированию85
4.4.1 Подготовка эксперимента 85
4.4.2 Описание результатов эксперимента 86
4.4.3 Результаты дизассемблирования 90
4.5 Определение размера требуемых ресурсов вычислительной системы 91
4.6 Показатели применимости разработанного метода защиты программных средств 99
4.7 Выводы 101
Заключение 103
Список использованной литературы 106
Преобразование форматирования самый простой способ запутывающих преобразований, изменяющий структуру кода программы таким образом, чтобы он стал не читабельным, менее информативным и трудным для изучения, и применимы только для запутывания программ на высоком уровне. Также, учитывая открытость семантики ПС определяющее свойство уязвимости, такие преобразования не устойчивы к семантическому или синтаксическому анализу.
2.2.2 Преобразования структур данных
К преобразованиям структур данных относятся преобразование типов данных и структуры данных, изменение интерпретации данных определенного типа, изменение срока использования хранилищ данных, объединение переменных, реструктурирование и переупорядочивание массивов. Такие преобразования эффективны в том случаи, если они применяются в комбиниро-
34 вании с другими методами запутывания, т.к. учитывая свойства уязвимости ПС (отсутствие независимости функционирования ПС на уровне операционной системы и открытость семантики обращений к операционной системе) легко определить зависимость выполнения ПС по данным.
2.2.3 Преобразования потока управления
Преобразования потока управления изменяют граф потока управления одной функции. Они могут приводить к созданию в программе новых функций. В работе [71, 86] приведено описание преобразований потока управления.
Открытая вставка функций (function inlining). Данное преобразование заключается в том, что тело функции подставляется в точку вызова функции. Данное преобразование является стандартным для оптимизирующих компиляторов. Это преобразование одностороннее, то есть по преобразованной программе автоматически восстановить вставленные функции невозможно.
Вынос группы операторов (function outlining). Данное преобразование является обратным к предыдущему и хорошо дополняет его. Некоторая группа операторов исходной программы выделяется в отдельную функцию. При необходимости создаются формальные параметры. Преобразование может быть легко обращено компилятором, который может подставлять тела функций в точки их вызова.
Отметим, что выделение операторов в отдельную функцию является достаточно сложной задачей, требующей проведения глубокого анализа графа потока управления и потока данных с учётом указателей, чтобы преобразование не нарушило работу программы.
Непрозрачные предикаты (opaque predicates). Данные преобразования основываются на введении непрозрачных переменных и предикатов. Сложность анализа непрозрачных предикатов и переменных обеспечивает устойчивость таких преобразований к анализу.
35 Определение. Переменная v является непрозрачной, если существует свойство Р относительно этой переменной, которое априори известно в момент запутывания программы, но трудно устанавливаемо после того, как запутывание завершено. То есть, предикат Н называется непрозрачным, если его значение известно только в процессе запутывания программы, но после того, как запутывание завершено определение его значения становится трудным.
Обозначим непрозрачный предикат, который всегда имеет значение «ложь» (false) как H{f), а предикат, который всегда имеет значение «истина» (true), как H{t). Тогда непрозрачный предикат H(t,f) может принимать любое из этих двух значений, и в момент запутывания текущее значение не известно.
Непрозрачные предикаты могут быть:
- локальными - вычисления содержаться внутри одиночного выражения;
- глобальными - вычисления содержаться внутри одной процедуры (функции);
- межпроцедурными - вычисления содержаться внутри различных процедур (функций).
В работах [84, 87, 101] предложены методы построения непрозрачных предикатов и переменных, основанные на "встраивании" в программу вычислительно сложных задач.
Возможные способы введения непрозрачных предикатов и непрозрачных выражений:
- использование разных способов доступа к элементам массива;
- использование указателей на динамические структуры;
- конструирование булевых выражений специального вида;
- построение сложных булевых выражений с помощью эквивалентных преобразований;
36 - использование комбинаторных тождеств.
Трансформация фрагмента кода программы с помощью непрозрачных предикатов приведена на рис. 2.2.
На рис. 2.2(a) блок А программы Pr, разбит на два независимых блока АХ,А2, которые соединены по средством непрозрачного предиката возвращающего всегда значение «истина» Н(t). В результате трансформации такого рода возникает представление того, что блок А2 не всегда выполняется, поэтому для того чтобы определить условия выполнения блока А2, необходимо узнать значение, которое возвращает используемый непрозрачный предикат H{t).
На рис. 2.2(6) помимо блока А2 используется еще один блок, над которым был произведен процесс запутывания блок А2 , то есть блок А2 и А2 имеют различный код, но выполняют одинаковые функции, следовательно, можно утверждать, что А2 = А2 , и поэтому неважно какой из этих блоков будет выполнен в процессе работы программы. Из этого следует, что для соединения блока Ах с А2 и А2 эффективно будет использовать непрозрачный предикат, который может возвратить любое из значений, а именно «истина» или «ложь» H(t,f).
На рис. 2.2(b) используется новый блок Аъ, который содержит произвольный набор, каких либо операций (недостижимый код), так как сами блоки А{ и А^ соединены по средством непрозрачного предиката возвращающего всегда значение «ложь» H{f) - это затрудняет анализ.
37
A2=\T A2*A3
а) б) в)
Рисунок 2.2 - Способы внесения непрозрачных предикатов
Эффективность запутывающих преобразований потока управления в основном зависит от используемых непрозрачных предикат. Это вынуждает создавать как можно сложные для изучения, и простые, гибкие в использовании непрозрачные предикаты. Также не маловажную роль имеет время их выполнения и количество выполняемых операций, помимо всего этого предикат должен не значительно отличаться от тех функций, которые выполняет сама программа, и не должен содержать чрезмерное количество вычислений т.к. тогда его можно легко обнаружить. Для устойчивости к статическому анализу используют устойчивые непрозрачные предикаты, которые позволяют использовать недостатки технологии статического анализа.
Основная идея устойчивых непрозрачных предикатов состоит в том, что в программу, в процессе запутывания добавляется код, который создает набор динамических структур, а также глобальных указателей. Такие преобразования с указателями, и структурами могут быть добавлены в разные участки программы. При этом существующие алгоритмы статического анализа будут не эффективны.
Внесение недостижимого кода (adding unreachable code) [71, 86]. Если в программу внесены непрозрачные предикаты видов #(/) или H(t), ветки
условия, соответствующие условию "истина" в первом случае и условию "ложь" во втором случае, никогда не будут выполняться. Фрагмент программы, который никогда не выполняется, называется недостижимым кодом. Эти ветки могут быть заполнены произвольными вычислениями, которые могут
38 быть похожи на действительно выполняемый код. Поскольку недостижимый код никогда не выполняется, данное преобразование влияет только на размер запутанной программы, но не на скорость её выполнения. Общая задача обнаружения недостижимого кода алгоритмически неразрешима. Это значит, что для выявления недостижимого кода должны применяться методы, основанные на статистическом анализе программы.
Внесение мёртвого кода (adding dead code). В отличие от недостижимого кода, мёртвый код в программе выполняется, но его выполнение никак не влияет на результат работы программы. При внесении мёртвого кода обязательно должно выполняться условие, что вставляемый фрагмент не может влиять на код, который вычисляет значение функции. Это значит, что мёртвый код не может иметь побочного эффекта, даже в виде модификации глобальных переменных, не может изменять окружение работающей программы, не может выполнять никаких операций, которые могут вызвать исключение в работе программы.
Внесение избыточного кода (adding redundant code). Избыточный код, в отличие от мёртвого кода выполняется, и результат его выполнения используется в дальнейшем в программе, но такой код можно упростить или совсем удалить, так как вычисляется либо константное значение, либо значение, уже вычисленное ранее. Для внесения избыточного кода можно использовать алгебраические преобразования выражений исходной программы или введение в программу математических тождеств.
Подобные алгебраические преобразования ограничены целыми значениями, так как при выполнении операций с плавающей точкой возникает проблема накопления ошибки вычислений.
Преобразование сводимого графа потока управления к несводимому (transforming reducible to non-reducible flow graph). Когда целевой язык (байт-код или машинный язык) более выразителен, чем исходный, можно использовать преобразования, "противоречащие" структуре исходного языка. В результате таких преобразований получаются последовательности инструкций
39 целевого языка, не соответствующие ни одной из конструкций исходного языка.
Недостатком таких преобразований является то, что с помощью статических или статистических методов анализа можно определить значение непрозрачных предикатов, использованных при запутывании, и устранить никогда не выполняющиеся переходы.
Устранение библиотечных вызовов (eliminating library calls). Большинство программ используют стандартные библиотеки. Поскольку семантика библиотечных функций хорошо известна, такие вызовы могут дать полезную информацию при обратной инженерии программ.
Переплетение функции (function interleaving). Данное преобразование объединяет две или более функций в одну функцию. Списки параметров исходных функций объединяются, и к ним добавляется ещё один параметр, который позволяет определить, какая функция в действительности выполняется.
Клонирование функций (function cloning). При обратной инженерии функций в первую очередь изучается сигнатура функции, а также то, как эта функция используется, в каких местах программы, с какими параметрами, и в каком окружении вызывается. Анализ контекста использования функции можно затруднить, если каждый вызов некоторой функции будет выглядеть как вызов какой-то другой, каждый раз новой функции. Может быть создано несколько клонов функции, и к каждому из клонов будет применён разный набор запутывающих преобразований.
Развёртка циклов (loop unrolling). Преобразование заключается в том, что тело цикла размножается два или более раз, условие выхода из цикла и оператор приращения счётчика соответствующим образом модифицируются. Если количество повторений цикла известно в момент компиляции, то цикл может быть развёрнут полностью.
40
Разложение циклов (loop fission). Разложение циклов состоит в том, что цикл со сложным телом разбивается на несколько отдельных циклов с простыми телами и с тем же пространством интегрирования.
Реструктуризация графа потока управления. Структура графа потока управления, наличие характерных шаблонов для циклов, условных операторов и т. д. предоставляет возможность исследования структуры программы при ее анализе. Например, по повторяющимся конструкциям графа потока управления можно легко установить, что над функцией было выполнено преобразование развёртки циклов, а далее можно проанализировать развёрнутые итерации цикла для выделения индуктивных переменных и свёртки цикла. В качестве меры противодействия может быть применено такое преобразование графа потока управления, которое приводит граф к однородному (плоскому) виду [71, 84, 102]. Операторы передачи управления на следующие за ними базовые блоки, расположенные на концах базовых блоков, заменяются на операторы передачи управления на специально созданный базовый блок диспетчера, который по предыдущему базовому блоку и управляющим переменным вычисляет следующий блок и передаёт на него управление. Технически это может быть сделано перенумерованием всех базовых блоков и введением новой переменной.
В работах [100-102] предлагается метод запутывания, и описывается его реализация в инструменте для запутывания программ на языке Си.
Описание процесса запутывания каждой такой процедуры состоит из трех этапов:
- создание графа потока управления этой процедуры множеством блоков и множеством связей соединяющих их, после чего граф разбивается, путем замены циклических конструкций в нем на конструкции типа (условие) if goto, пример для программы на языке Си приведен на рис. 2.3;
- нумерация всех блоков в графе, и добавление в код процедуры переменной (например, swVar) хранящей номер следующего выполняемого блока;
41
РОССИЙСКАЯ
ГО СУД,Л; "Л П ЕЯ Wf.'-
- приведение графа к однородному (плоскому) виду (рис. 2.4).
Рассмотренный вариант алгоритма запутывания не устойчив к статическому анализу, так как определить следующий выполняемый блок, нетрудно (в приведенном примере он будет храниться в переменной swVar). Поэтому, для того чтобы затруднить статический анализ, номера базовых блоков помещаются в массив (например, @gg), каждый элемент которого индексируется несколькими разными способами, например содержащий помимо номеров блоков, не нужную информацию, в результате запись $swVar=S6, можно заменить на $swVar=$gg [$gg [1] +$gg [3] ]. Таким образом, для статического прослеживания порядка выполнения базовых блоков необходимо провести анализ указателей.
ту $а=1; ту $Ь=2;
while ($а<10) {
$b=$a+$b;
if ($b>10)
{b—;}
a++;
}
return $b;
Граф потока управления
Исходный текст про-
граммы
Рисунок 2.3 - Разбитый граф потока управления
42
| my$a=l my$b=2 |
|
| ||||||||||||
| * |
|
| ||||||||||||
| my $swVar=Sl |
|
| ||||||||||||
| * |
|
| ||||||||||||
case: goto SswVar |
|
| |||||||||||||
|
| 1 | 1 |
|
| ||||||||||
|
| 1 |
|
|
| ||||||||||
|
|
|
|
|
|
|
| ||||||||
Sl_. , ' | ■ |
| 47 І |
| . | £4. | і |
| SS |
| ЧЛ | ||||
if(not($a<10)) {$swVar=S6} else {$swVar=S2} |
| $b=Sa+Sb $swVar=S3 |
| if(not($b>10)) {$swVar=S5} else {$swVar=S4} |
| $b-$swVar=S5 |
| $a++ $swVar=Sl |
| return $b | |||||
|
| і |
|
|
|
|
| l |
|
|
| ||||
|
|
|
|
|
|
|
| ||||||||
її її |
|
| |||||||||||||
| Y ▼! | ■+ + * |
|
|
| ||||||||||
| goto case |
|
|
Информация о работе Метод защиты программных средств на основе запутывающих преобразований