Рефераты

Защита информации в системах дистанционного обучения с монопольным доступом

разработки на языке С++ для ОС Microsoft Windows. Немаловажным фактором

является ее поддержка такими утилитами, как Visual Assist, BoundsChecker,

которые в свою очередь позволяют создавать программы более быстро и

качественно. Компилятор Visual C++ генерирует достаточно оптимизированный

код, что весьма важно для разрабатываемого приложения.

3.1.3. Краткая характеристика библиотеки ATL

Библиотека активных шаблонов (ATL) представляет собой основу для

создания небольших СОМ - компонентов. В ATL использованы новые возможности

шаблонов, добавленные в C++. Исходные тексты этой библиотеки поставляются в

составе системы разработки Visual C++. Кроме того, в эту систему разработки

введено множество мастеров Visual C++, что облегчает начальный этап

создания ATL-проектов.

Библиотека ATL обеспечивает реализацию ключевых возможностей СОМ

компонентов. Выполнения многих рутинных процедур, с которыми мы столкнулись

при разработке последнего примера, можно избежать за счет использования

классов шаблонов ATL. Приведем далеко не полный список функций ATL.

Некоторые из них будут рассмотрены в этой главе.

. Утилита AppWizard, предназначенная для создания первичного ATL-

проекта.

. Мастер объектов, используемый для добавления в проект компонентов

различных типов.

. Поддержка по умолчанию основных интерфейсов COM, таких как IUnknown и

IClassFactory.

. Поддержка механизма транспортировки пользовательского интерфейса.

. Поддержка базового механизма диспетчеризации (автоматизации) и

двунаправленного интерфейса.

. Существенная поддержка разработки небольших элементов управления

ActiveX.

Основной задачей ATL является облегчение создания небольших СОМ-

компонентов. Задача MFC — ускорение разработки больших Windows-приложений.

Функции MFC и ATL несколько перекрываются, в первую очередь в области

поддержки OLE и ActiveX.

Поскольку разрабатываемый модуль защиты не велик и не требует

какой либо работы с графическим интерфейсом, то вполне естественно выбрать

его, а не более тяжелый и излишний по функциональности MFC.

3.1.4. Краткая характеристика библиотеки ZLIB

Библиотека ZLIB представляет собой небольшую и удобную библиотеку на

языке С. Ее назначение – упаковка и распаковка данных. Поскольку она

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

в разрабатываемом модуле. Также отметим, что эта библиотека является

свободно распространяемой, что не влечет за собой нарушения авторских прав.

3.2. Полиморфный генератор алгоритмов шифрования

Рассмотрим построение генератора полиморфных алгоритмов шифрования и

расшифрования. Эти алгоритмы всегда генерируются парами, механизм их

генерации весьма схож и осуществляется одним кодом. Разница только в том,

что используются блоки, производящие обратные преобразования. Вначале

рассмотрим, как вообще выглядят общий алгоритм шифрования/расшифрования.

Затем покажем, как выглядит готовый код алгоритма шифрования/расшифрования,

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

приведет отладочный вывод виртуальный машины, демонстрирующий работу

алгоритмов шифрования/расшифрования. Затем будет рассмотрен непосредственно

сам алгоритм построения полиморфного кода, и подсчитана вероятность

генерации одинаковых алгоритмов и пути повышения сложности полиморфных

алгоритмов.

3.2.1. Общие принципы работы полиморфных алгоритмов шифрования и

расшифрования

Представим генерируемые алгоритмы шифрования/расшифрования в

общем виде. Они состоят из 8 функциональных блоков, некоторые из которых

могут повторяться. На рисунке 5 приведена абстрактная схема работы

алгоритма шифрования/расшифрования. Повторяющиеся блоки обозначены

эллипсами, находящимися под квадратами. Количество таких блоков выбирается

случайно при генерации каждой новой пары алгоритмов. Функциональные блоки и

их номер отмечены числом в маленьком прямоугольнике, расположенным в правом

верхнем углу больших блоков.

Сразу отметим, что при своей работе виртуальная машина

использует виртуальные регистры и память. Начальное содержимое виртуальной

памяти, как и сам сгенерированный алгоритм, хранится в файле. Например,

именно в виртуальной памяти может быть записано, сколько байт необходимо

расшифровать. Некоторые виртуальные регистры и виртуальные ячейки памяти

содержат мусор и не используются или используются в холостых блоках.

Холостые блоки состоят из одной или более базовых инструкций виртуальной

машины. Они не являются функциональными блоками, и их описание будет

опушено. Холостым блокам будет уделено внимание в следующем разделе. На

схеме произвольные регистры/ячейки памяти обозначаются как буква А с

цифрой. Полиморфный генератор случайным образом выбирает, какой же именно

регистр или ячейка памяти будет задействована в каждом конкретном алгоритме

шифрования/расшифрования. Рассмотрим теперь каждый из функциональных блоков

более подробно.

[pic]

Рисунок 5. Алгоритм шифрования/расшифрования в общем виде.

Блок 1 заносит в виртуальный регистр или переменную (обозначим

ее как A1) адрес шифруемого/расшифруемого блока данных. Для виртуальной

машины этот адрес на самом деле всегда является нулем. Дело в том, что

когда происходит выполнение виртуальной инструкции модификации данных, то

виртуальная машина добавляет к этому адресу настоящий адрес в памяти и уже

с ним производит операции. Можно представить A1 как индекс в массиве

шифруемых/расшифруемых данных, адресуемых с нуля.

Блок 2 заносит в виртуальный регистр или переменную (обозначим

ее как A2) размер блока данных. А2 выполняет роль счетчика в цикле

преобразования данных. Заметим, что ее значение всегда в 4 раза меньше, чем

настоящий размер шифруемых/расшифруемых данных. Это связано с тем, что

полиморфные алгоритмы всегда работают с блоками данных, кратных по размеру

4 байтам. Причем, операции преобразования выполняются над блоками, кратными

4 байтам. О выравнивании данных по 4 байта заботятся более высокоуровневые

механизмы, использующие виртуальную машину и полиморфные алгоритмы для

шифрования и расшифрования данных. Возникает вопрос, откуда алгоритму

"знать", какого размера блок ему необходимо зашифровать, ведь при его

генерации такой информации просто нет. Необходимое значение он просто берет

из ячейки памяти. Виртуальная машина памяти знает именно об этой ячейке

памяти и перед началом выполнения полиморфного алгоритма заносит туда

необходимое значение.

Блок 3 помещает в виртуальный регистр или переменную (обозначим

ее как A3) константу, участвующую в преобразовании. Эта константа,

возможно, затем и не будет использована для преобразования данных, все

зависит от того, какой код будет сгенерирован. Блок 3 может быть повторен

несколько раз. Над данными осуществляется целый набор различных

преобразований, и в каждом из них участвуют различные регистры/переменные,

инициализированные в блоке 3.

Блок 4 можно назвать основным. Именно он, а, точнее сказать,

набор этих блоков производит шифрование/расшифрование данных. Количество

этих блоков случайно и равно количеству блоков номер 3. При преобразованиях

не обязательно будет использовано значение из A3. Например, вместо A3 может

использоваться константа или значение из счетчика. На данный момент

полиморфный генератор поддерживает 3 вида преобразований: побитовое

"исключающее или" (XOR), сложение и вычитание. Набор этих преобразование

можно легко расширить, главное, чтобы такое преобразование имело обратную

операцию.

Блок 5 служит для увеличения A1 на единицу. Как и во всех

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

использованием различных элементарных инструкций виртуальной машины.

Блок 6 организует цикл. Он уменьшает значение A2 на единицу, и

если результат не равен 0, то виртуальная машина переходит к выполнению

четвертого блока. На самом деле управление может быть передано на один из

холостых блоков между блоком 3 и 4, но с функциональной точки зрения это

значения не имеет.

Блок 7 производит проверку ограничения по времени использования

алгоритма. Код по проверке на ограничение по времени относится к холостым

командам и, на самом деле, может присутствовать и выполнятся в коде большое

количество раз. То, что он относится к холостым блокам кода вовсе не

значит, что он не будет нести функциональной нагрузки. Он будет

действительно проверять ограничение, но он, как и другие холостые блоки,

может располагаться произвольным образом в пустых промежутках между

функциональными блоками. Поскольку этот блок может теоретически никогда не

встретиться среди холостых блоков, то хоть один раз его следует выполнить.

Именно поэтому он и вынесен как один из функциональных блоков. Если же при

генерации алгоритма от генератора не требуется ограничение по времени, то в

качестве аргумента к виртуальной команде проверки времени используется

специальное число.

Блок 8 завершает работу алгоритма.

3.2.2. Виртуальная машина для выполнения полиморфных алгоритмов

Для начала приведем список инструкций, поддерживаемых на данный момент

виртуальной машиной. Коды этих инструкций имеют тип E_OPERATION и

определены в файле p_enums.h следующим образом:

enum E_OPERATION // Инструкции

{

EO_ERROR = -1, // Недопустимая инструкция

EO_EXIT_0, EO_EXIT_1, EO_EXIT_2, // Конец работы

EO_NOP_0, EO_NOP_1, EO_NOP_2, EO_NOP_3, // Пустые команды

EO_TEST_TIME_0, EO_TEST_TIME_1, // Контроль времени

EO_MOV, EO_XCHG, // Пересылка данных

EO_PUSH, EO_POP, // Работа со стеком

EO_XOR, EO_AND, EO_OR, EO_NOT, // Логические операции

EO_ADD, EO_SUB, EO_MUL, EO_DIV, EO_NEG, // Арифметические операции

EO_INC, EO_DEC,

EO_TEST, EO_CMP, // Операции сравнения

// (влияют на флаги)

EO_JMP, EO_CALL, EO_RET, // Операторы безусловного

перехода

EO_JZ, EO_JNZ, EO_JA, EO_JNA, // Условные переходы

};

В таблице 1 приведена информация по этим инструкциям и перечислены их

аргументы.

Таблица 1. Описание инструкций виртуальной машины.

|Название |Действие |

|EO_EXIT_0 |Команды завершения работы. После ее выполнения |

|EO_EXIT_1 |виртуальная машина остановится, и управление будет |

|EO_EXIT_2 |передано выше. Данные инструкции аргументов не имеют. |

|EO_TEST_TIME_0 |Команды контроля времени. Имеют один аргумент - |

|EO_TEST_TIME_1 |последний доступный день использования. |

|EO_MOV |Команда пересылки данных. Имеет два аргумента – источник|

| |и получатель. |

|EO_XCHG |Данная команда обменивает значения двух регистров или |

| |ячеек памяти, переданных в двух аргументах. |

|EO_PUSH |Сохраняет переданный аргумент в стеке. |

|EO_POP |Снимает значение с вершины стека и помещает в указанную |

| |ячейку памяти или регистр. |

|EO_XOR |Логическая операция XOR. Имеет два аргумента. Результат |

| |помещается в ячейку памяти или регистр, переданный в |

| |качестве первого аргумента. |

Продолжение таблицы 1. Описание инструкций виртуальной машины.

|Название |Действие |

|EO_AND |Логическая операция AND. Имеет два аргумента. Результат |

| |помещается в ячейку памяти или регистр, переданный в |

| |качестве первого аргумента. |

|EO_OR |Логическая операция OR. Имеет два аргумента. Результат |

| |помещается в ячейку памяти или регистр, переданный в |

| |качестве первого аргумента. |

|EO_NOT |Логическая операция NOT. Имеет один аргумент. Результат |

| |помещается в ячейку памяти или регистр, переданный в |

| |качестве аргумента. |

|EO_ADD |Арифметическая операция сложения. Имеет два аргумента. |

| |Результат помещается в ячейку памяти или регистр, |

| |переданный в качестве первого аргумента. |

|EO_SUB |Арифметическая операция вычитания. Имеет два аргумента. |

| |Результат помещается в ячейку памяти или регистр, |

| |переданный в качестве первого аргумента. |

|EO_MUL |Арифметическая операция умножения. Имеет два аргумента. |

| |Результат помещается в ячейку памяти или регистр, |

| |переданный в качестве первого аргумента. |

|EO_DIV |Арифметическая операция деления. Имеет два аргумента. |

| |Результат помещается в ячейку памяти или регистр, |

| |переданный в качестве первого аргумента. |

|EO_NEG |Арифметическая операция изменения знака. Имеет один |

| |аргумент. Результат помещается в ячейку памяти или |

| |регистр, переданный в качестве аргумента. |

|EO_INC |Увеличивает значение ячейки памяти или регистра на |

| |единицу, передаваемой в единственном аргументе. |

|EO_DEC |Уменьшает значение ячейки памяти или регистра на |

| |единицу, передаваемой в единственном аргументе. |

|EO_TEST |Операция сравнения двух аргументов на равенство. Если |

| |аргументы равны, то флаг ZERO выставляется в true, в |

| |противном случае в false. |

|EO_CMP |Операция сравнения двух аргументов. Если аргументы |

| |равны, то флаг ZERO выставляется в true, в противном |

| |случае в false. Если первый аргумент меньше второго, то |

| |флаг ABOVE выставляется в true, в противном случае в |

| |false. |

Продолжение таблицы 1. Описание инструкций виртуальной машины.

|Название |Действие |

|EO_JMP |Данная инструкция осуществляет безусловный переход по |

| |адресу, указанному в качестве аргумента. |

|EO_CALL |Данная инструкция осуществляет вызов функции по адресу, |

| |указанному в качестве аргумента. |

|EO_RET |Данная инструкция возвращает управление предыдущей |

| |функции. Аргументов нет. |

|EO_JZ |Условный переход по адресу, указанному в качестве |

| |аргумента. Условием является ZERO == true. |

|EO_JNZ |Условный переход по адресу, указанному в качестве |

| |аргумента. Условием является ZERO == false. |

|EO_JA |Условный переход по адресу, указанному в качестве |

| |аргумента. Условием является ABOVE == true. |

|EO_JNA |Условием является ABOVE == false. |

Отметим, что аргументы могут быть следующих типов:

EOP_REG – Регистр

EOP_REF_REG – Память по адресу в регистре.

EOP_VAR – Переменная.

EOP_REF_VAR – Память по адресу в переменной.

EOP_CONST – Константное значение.

EOP_RAND – Случайное число.

Перечисленные типы объявлены в файле p_enums.h.

Для примера, приведем как будет выгладить код сложения регистра N 1 с

константой 0x12345:

DWORD AddRegAndConst[] = { EO_ADD, EOP_REG , 1, EOP_CONST, 0x12345 };

Для наглядной демонстрации, как происходит выполнение кода в

виртуальной машине при шифровании/расшифровании данных, приведем отрывок из

отладочного отчета. Каждое действие в отладочном режиме протоколируется в

файле uniprot.log. Благодаря этому, было легко отлаживать механизм

генерации полиморфных алгоритмов и саму работу алгоритмов. Дополнительным

результатом создания механизма протоколирования стала возможность показать,

как происходит выполнение алгоритма шифрования расшифрования. Ниже приведен

отрывок из файла uniprot.log, относящийся к процессу шифрования данных. С

целью сокращения объема текста, убраны дублирующийся вывод внутри цикла.

Также при генерации этого алгоритма были выставлена вложенность шифрования

равная единицы и почти убраны холостые блоки.

=== Start TranslateOperations ===

mov RAND ==> REG_2

xchg REG_2 VAR_16 REG_2 VAR_16

mov CONST ==> VAR_11

dec VAR_11 ==> VAR_11

cmp VAR_11 CONST

jnz CONST

mov RAND ==> REG_6

xchg VAR_14 VAR_12 VAR_14 VAR_12

mov CONST ==> VAR_15

add VAR_15 VAR_18 ==> VAR_15

mov RAND ==> REG_4

mov CONST ==> VAR_19

add VAR_19 VAR_9 ==> VAR_19

add REG_8 REG_7 ==> REG_8

xchg REG_2 VAR_13 REG_2 VAR_13

Эта часть повторяется много раз:

mov RAND ==> REG_6

xor REF_VAR_11 VAR_14 ==> REF_VAR_11

mov RAND ==> REG_4

mov RAND ==> REG_9

xor REF_VAR_11 VAR_15 ==> REF_VAR_11

sub VAR_11 CONST ==> VAR_11

mov RAND ==> REG_7

dec VAR_14 ==> VAR_14

cmp VAR_14 CONST

jnz CONST

…………..

mov RAND ==> REG_1

add REG_9 REG_6 ==> REG_9

test_time1 VAR_10

OK TIME (continue)

exit

3.2.3. Генератор полиморфного кода

3.2.3.1. Блочная структура полиморфного кода

Основу генератора полиморфного кода составляют таблицы выбора. Как

уже было описано ранее, алгоритм шифрования и расшифрования состоит из

восьми обязательных функциональных блоков. Каждый блок хоть и выполнит

строго определенную функцию, но может быть реализован многими способами.

Причем с использованием различных виртуальных регистров и виртуальных ячеек

памяти. Возможные комбинации реализации блока описаны в специальных

таблицах следующего вида, о которых будет сказано позднее.

//--------------------------------------------------------------

// Блок N5. (x1)

// Служит для организации цикла.

// ES_VARIABLE_0 – ячейка, которая может быть занята под счетчик.

// ES_REG_0 - регистр, который может быть занят под счетчик.

// ES_ADDRESS_0 - куда осуществить переход для повтора цикла.

BLOCK_START(05_00)

EO_DEC, EOP_VAR, ES_VARIABLE_0,

EO_CMP, EOP_VAR, ES_VARIABLE_0, EOP_CONST, 0,

EO_JNZ, EOP_CONST, ES_ADDRESS_0

BLOCK_END(05_00)

BLOCK_START(05_01)

EO_DEC, EOP_REG, ES_REG_0,

EO_CMP, EOP_REG, ES_REG_0, EOP_CONST, 0,

EO_JNZ, EOP_CONST, ES_ADDRESS_0

BLOCK_END(05_01)

BLOCKS_START(05)

BLOCK(05_00)

BLOCK(05_01)

BLOCKS_END(05)

BLOCKS_SIZE_START(05)

BLOCK_SIZE(05_00)

BLOCK_SIZE(05_01)

BLOCKS_SIZE_END(05)

//--------------------------------------------------------------

Под полиморфизмом понимается не только выбор и сочетание

произвольного набора блоков, но и их расположение в памяти. Стоит отметить,

что просто построение алгоритма из набора различных блоков достаточно

сложная процедура. Так как необходимо учитывать использование виртуальных

регистров и виртуальной памяти, используемых в разных блоках по разному.

Например, использование определенного регистра в качестве счетчика во

втором блоке автоматически приводит к учету этой особенности и назначению

этого регистра во всех других блоках.

Как было сказано ранее, алгоритмы шифрования и расшифрования

генерируются одним алгоритмом и функционально различаются только блоками

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

шифрования и расшифрования могут быть совершенно непохожи друг на друга и

состоять из разного набора инструкций виртуальной машины.

Вернемся к распределению блоков в памяти. Помимо того, что каждый

алгоритм состоит из произвольного набора функциональных блоков, эти блоки

не имеют фиксированного места расположения. Скажем, что под весь алгоритм

выделено 200 байт, а размер всех блоков в сумме составляет 100 байт. В

результате положение этих блоков как бы "плавает" от одного

сгенерированного алгоритма к другому. Должно выполняться лишь одно условие:

соблюдение четкой последовательности расположения блоков. То есть, адрес

расположения блока с большим номером не может быть меньше, чем адрес блока

с меньшим номером. Для большей наглядности приведем рисунок 6.

[pic]Рисунок 6. Расположение функциональных блоков в памяти.

Белым цветом показаны все функциональные блоки. Серым цветом отмечены

пустые места, которые будут заполнены произвольными холостыми блоками.

Может получиться, например, и такая картина распределения блоков, когда

между некоторыми нет промежутка заполняемого холостыми блоками. Такая

ситуация показана на рисунке 7.

[pic]Рисунок 7. Плотное расположение функциональных блоков в памяти.

Как функциональные блоки, так и холостые, могут иметь различную

длину. После случайного расположения функциональных блоков происходит

заполнение пустых пространств между ними холостыми блоками. Причем,

существуют холостые блоки длиной 1, для того чтобы можно было заполнить

пустые места в любом случае. Размер памяти, выделенный под создаваемый код

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

160 до 200 байт. Это с запасом покрывает максимально необходимый размер

памяти, необходимый для размещения 8 самых больших функциональных блоков из

всех возможных, и оставляет место под холостые блоки. Более большой

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

замедлить процесс шифрования и расшифрования. По этому лучше всего

придерживаться разумного баланса.

3.2.3.2. Алгоритм генерации полиморфного кода

Опишем теперь пошагово как работает генератор полиморфного кода.

1. На первом этапе выбираются характеристики будущих алгоритмов. К ним

относятся:

a) размер памяти, выделенной под код;

б) в каких регистрах или ячейках будут располагаться указатели на

модифицируемый код;

г) сколько раз будут повторяться функциональные блоки 3 и 4;

д) в каких регистрах или ячейках будут располагаться счетчики циклов;

При этом количество повторений блоков 3 и 4 должно быть одинаковым и для

алгоритма шифрования и для алгоритма расшифрования, так как каждой

команде преобразования данных при шифровании должна быть сопоставлена

обратная команда в алгоритме расшифрования.

2. Виртуальная память, используемая в алгоритме, заполняется случайными

значения.

3. Создается 1-ый функциональный блок и помещается в промежуточное

хранилище.

а) Случайным образом ищется подходящий первый блок. Критерий поиска –

блок должен использовать регистр или ячейку памяти под указатель, в

зависимости от того какие характеристики были выбраны на первом шаге

(пункт б).

б) В код блока подставляется соответствующий номер регистра или адрес

виртуальной ячейки памяти.

4. Создается 2-ой функциональный блок и помещается в промежуточное

хранилище. Алгоритм создания подобен алгоритму, описанному в шаге 3. Но

только теперь подставляется не только номер регистра или ячейки памяти,

куда помещается значение, но и адрес памяти с источником. В эту ячейку

памяти в дальнейшем виртуальная машина будет помещать размер

шифруемой/расшифруемой области.

5. Необходимое количество раз создаются и помещаются в промежуточное

хранилище функциональные блоки под номером 3. Механизм их генерации также

схож с шагами 3 и 4. Отличием является то, что некоторые константы в коде

блока заменяются случайными числами. Например, эти значения при

шифровании или расшифровании будут складываться с преобразуемыми ячейками

памяти, вычитаться и так далее.

6. Подсчитывается размер уже сгенерированных блоков. Это число затем будет

использоваться для случайной генерации адреса начала блоков в цикле.

7. Рассчитывается размер памяти, который будет выделен под уже

сгенерированные блоки (расположенные до цикла) с резервированием места

под холостые блоки. Также подсчитывается адрес первого блока в цикле.

8. Необходимое количество раз создаются и помещается в промежуточное

хранилище функциональные блоки под номером 3. Это шаг несколько сложнее,

чем все другие. Здесь весьма сильная зависимость между сгенерированным

кодом шифрования и расшифрования. В коде расшифрования используются

обратные по действию операции относительно операций шифрования. При этом

они располагаются в обратной последовательности.

9. Создается 5-ый функциональный блок и помещается в промежуточное

хранилище.

10. Создается 6-ой функциональный блок и помещается в промежуточное

хранилище. Это блок, организующий цикл, поэтому он использует адреса,

рассчитанные на шаге 7.

11. Создается 7-ой функциональный блок и помещается в промежуточное

хранилище.

12. Создается 8-ой функциональный блок и помещается в промежуточное

хранилище.

13. Созданные функциональные блоки размещаются в одной области памяти с

промежутками случайного размера. После чего получается картина подобная

тем, что приведены на рисунках 6 и 7.

14. Оставшиеся промежутки заполняются случайно выбранными холостыми

блоками. При этом эти блоки также подвергаются модификации кода.

Например, подставляются случайные, но неиспользуемые номера регистров,

записываются случайные константы и так далее.

15. Происходит запись в файл необходимых идентификаторов, структур,

различных данных и самого полиморфного кода. В результате мы получаем то,

что называется файлом с полиморфный алгоритмом.

3.2.3.3. Таблицы блоков для генерации полиморфного кода

Выше неоднократно упоминались таблицы блоков, среди которых происходит

выбор. Приведем для примера часть таблицы с блоками N 1 и опишем ее

устройство.

//--------------------------------------------------------------

// Блок N0. (x1)

// Служит для инициализации указателя нулем.

// ES_VARIABLE_0 - ячейка которая может быть занята под указатель.

// ES_REG_0 - регистр который может быть занят под указатель.

BLOCK_START(00_00)

EO_MOV, EOP_VAR, ES_VARIABLE_0, EOP_CONST, 0

BLOCK_END(00_00)

BLOCK_START(00_01)

EO_MOV, EOP_REG, ES_REG_0, EOP_CONST, 0

BLOCK_END(00_01)

BLOCK_START(00_02)

EO_PUSH, EOP_CONST, 0,

ES_RANDOM_NOP,

ES_RANDOM_NOP,

EO_POP, EOP_REG, ES_REG_0

BLOCK_END(00_02)

. . . . . . .

BLOCKS_START(00)

BLOCK(00_00)

BLOCK(00_01)

BLOCK(00_02)

BLOCK(00_03)

. . . . .

BLOCKS_END(00)

BLOCKS_SIZE_START(00)

BLOCK_SIZE(00_00)

BLOCK_SIZE(00_01)

BLOCK_SIZE(00_02)

BLOCK_SIZE(00_03)

. . . . .

BLOCKS_SIZE_END(00)

//--------------------------------------------------------------

Рассмотрим строку "BLOCK_START(00_00)". BLOCK_START представляет

собой макрос который делает код более понятным и раскрывается так:

#define BLOCK_START(num) const static int block_##num [] = {

BLOCKS_END раскрывается в:

#define BLOCK_END(num) }; const size_t sizeBlock_##num =\

CALC_ARRAY_SIZE(block_##num);

Таким образом, BLOCK_START и BLOCK_END позволяет получить именованный

массив и его длину. Это удобно для автоматического построения массива

указателей на блоки и их длину. Нам более интересны не эти вспомогательные

макросы, а следующая строка.

EO_MOV, EOP_VAR, ES_VARIABLE_0, EOP_CONST, 0

Она представляет собой один из вариантов реализации первого блока.

EO_MOV означает, что будет выполнена команда пересылки данных. EOP_VAR

означает, что запись будет производиться в ячейку памяти. Этот блок никогда

не станет выбранным, если при выборе характеристик алгоритма будет решено,

что под указатель необходимо использовать регистр. Если же будет принято

решение использовать ячейку памяти, то этот блок попадет в список из

которого затем случайным образом будет произведен выбор. ES_VARIABLE_0 это

идентификатор на место которого будет подставлен номер переменной,

используемой для хранения указателя. Этот номер также генерируется на этапе

выбора характеристик. EOP_CONST означает, что переменной будет присвоено

значение константы. Этим значением является 0.

Аналогичным образом интерпретируется строка: EO_MOV, EOP_REG,

ES_REG_0, EOP_CONST, 0. Но теперь вместо виртуальной ячейки памяти

выступает виртуальный регистр. Более интересным является следующий блок:

EO_PUSH, EOP_CONST, 0,

ES_RANDOM_NOP,

ES_RANDOM_NOP,

EO_POP, EOP_REG, ES_REG_0

Принцип его работы в следующем. На вершину стека помещается

константное значение равное 0. На место ES_RANDOM_NOP помещаются

произвольный холостой блок. В последней строке происходит получение

значение из стека и запись его в виртуальный регистр, выбранный под

указатель.

Макросы BLOCKS_START и BLOCKS_SIZE_START носят вспомогательный

характер и не представляют большого интереса. Они просто строят таблицы

адресов различных блоков и их размеров.

3.2.4. Уникальность генерируемого полиморфного алгоритма и сложность его

анализа

Важная идея в разрабатываемом модуле защиты заключена в построении

сложного для анализа полиморфного кода, что должно препятствовать

построению обратного алгоритма, так как в защищаемых системах часто просто

невозможно хранить ключи отдельно от данных. Если есть доступ к ключам, то

и увеличивается вероятность каким-либо образом произвести

несанкционированные действия. Из этого следует необходимость создания

сложных для анализа алгоритмов шифрования/расшифрования. Одним из этих

средств является виртуальная машина. Другим – использование полиморфных

алгоритмов. Это затрудняет возможности по анализу механизмов шифрования

данных, так как полный анализ одного алгоритма очень мало помогает в

анализе другого. Чем больше возможно вариантов построения полиморфного

кода, тем более трудоемкой становится процедура анализа. Следовательно,

можно сказать, что критерий надежности повышается с ростом количества

возможных вариантов полиморфного кода. Подсчитаем количество возможных

вариантов, который может сгенерировать разработанный генератор полиморфного

кода.

Вероятность генерации двух одинаковых пар составляет: (2^32*3)^5 (

3.5*10^50. Где 2^32 – случайно используемая константа для шифрования. 3 –

количество возможных операций над числом. 5 – максимальное количество

проходов для шифрования. Фактически это означает что два одинаковых

алгоритма не будут никогда сгенерированы этой системой. Но это не является

целью. Ведь то что не генерируются 2 одинаковых алгоритма, не так важно.

Важно что анализ таких разнородных механизмов шифрования/расшифрования

будет очень плохо поддаваться анализу.

Покажем на примере, что именно могут дать полиморфные алгоритмы.

Предположим кто-то задумал создать универсальный редактор отчетов о

выполненных работах, создаваемых АРМ студента. В этом отчете хранится

оценка о тестировании. Ее исправление и является целью. АРМ студента

шифрует файл с отчетом уникальным полиморфным алгоритмом, сгенерированным

специально для данного студента. Ключ расшифрования у студента не хранится.

Он находится у АРМ преподавателя и служит для идентификации, что студент

выполнил работу именно на своем АРМ. В противном случае файл с отчетом

просто не расшифруется.

Для обхода такой системы можно пойти двумя путями. Первый вариант

состоит в эмуляции системы генерации отчетов и использования имеющегося

файла с алгоритмом шифрования. Второй путь – это создание алгоритма

расшифрования по алгоритму шифрования. После чего файл с отчетом можно

будет легко расшифровать, модифицировать и вновь зашифровать. В обеих

случаях придется разбираться, как использовать предоставляемые COM сервисы

модуля защиты, что само по себе уже не простая задача. Но, допустим, это

было сделано, и теперь мы остановимся на других моментах.

В первом случае может понадобиться разрабатывать достаточно сложную

систему с целью эмуляции генератора отчета. Это очень труднореализуемо. В

каком-то смысле придется повторить большую часть функциональности АРМ

студента. Так, если в отчете будут храниться вопросы, которые были заданы

студенту, то, фактически, придется работать с этой базой вопросов и

случайно выбирать из них. В противном случае, если использовать строго

определенный набор, то у всех, кто воспользуется такой системой взлома,

будут совпадать отчеты. Это может привести к подозрению со стороны

преподавателя. Таким образом, в грамотно и сложно организованной АСДО этот

подход практически не применим.

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

Здесь на пути и встает многовариантность кода. Невозможно применить маску с

целью поиска функциональных блоков, а следовательно, и просто их выделить.

Можно только написать высокоинтеллектуальный анализатор кода, который

превратит алгоритм в псевдокод, а уже затем по нему построит обратный. Это

очень сложная задача. Причем, для написания такой программы придется

досконально изучить код виртуальной машины. В том случае, когда исходные

коды отсутствуют, все это может превратиться в непосильную задачу. Точнее

сказать, в слишком дорогой в своей реализации, и доступной в написании

только высококвалифицированному специалисту.

Если кто-то реализует второй вариант программы, то небольшого

расширения базы блоков в исходных кодах будет достаточно, чтобы всю работу

понадобилось проделать заново.

На мой взгляд, созданная система достаточно сложна в плане анализа и

может эффективно помочь защищать АСДО и другие программы от

несанкционированных действий.

3.3. Особенности реализации модуля защиты

Разрабатываемый модуль защиты Uniprot будет представлять собой файл

типа dynamic link library (DLL) с именем Uniprot.dll.

Для организации взаимодействия модуль защиты предоставляет набор

интерфейсов с использованием технологии COM. Для описания интерфейсов

используется специальный язык - IDL, по своей структуре очень похожий на

С++. В определении интерфейса описываются заголовки входящих в него функций

с указанием их имен, возвращаемых типов, входных и выходных параметров, а

Страницы: 1, 2, 3, 4, 5, 6


© 2010 БИБЛИОТЕКА РЕФЕРАТЫ