Программирование средства внедрения и анализа водяных знаков в исходные тексты программ
Лист
на реценцию
Содержание
Введение 4
1 Описание методов и средств решения задачи 6
1.1 Постановка задачи на курсовое проектирование 6
1.2 Общие аспекты проблемы авторского права 6
1.3 Современные методы защиты программного обеспечения 7
2 Методы внедрения водяных знаков 19
2.1 Исследование статистических свойств исполняемого кода 19
2.2 Предлагаемые методы внедрения водяных знаков 21
2.3 Оценка эффективности подстановок 24
3 Описание разработанного программного обеспечения 26
3.1 Общая структура 26
3.2 Проектирование базы данных 26
3.3 Описание основных компонентов 27
3.4 Описание алгоритма программы 30
4 Описание результатов работы 32
4.1 Описание главной формы программы 32
4.2 Описание результатов работы программы и выводы по ним 33
Заключение 35
Список использованных источников 36
Приложение А. Листинг программы 37
Введение
В
связи с широким
Самой серьезной проблемой, с которой сталкиваются разработчики программного обеспечения, является пиратство. Оно наносит им очень серьезный ущерб. Контрафактное программное обеспечение до сих пор можно найти в Интернете, на рынке и в магазинах, торгующих дисками. Таким образом, самим разработчикам тоже приходится бороться с пиратами. И самым, пожалуй, эффективным способом такой борьбы является защита своих программ от нелицензированного использования. На сегодняшний день разработано немало различных методов для решения этой задачи. Некоторые из них более надежны, другие - менее. Однако все они имеют свое право на существование. Ведь чем надежней защита, тем больше денег необходимо потратить на ее реализацию. Поэтому для разных продуктов необходимы различные подходы.
Одной из самых сложных задач является защита дорогих программ. Ведь чем дороже программное обеспечение, тем больше найдется желающих воспользоваться им бесплатно. Поэтому если пиратам удастся взломать установленную защиту и растиражировать софт на компакт-дисках по небольшой цене, то ущерб, нанесенный разработчикам, будет просто огромен. Поэтому профессиональное программное обеспечение необходимо хорошо защищать от нелицензированного использования.
В последнее время одним из направлений развития средств противодействия компьютерному пиратству стали исследования защиты ПО водяными знаками – средством, позволяющим доказать права собственности на программу целиком или некоторую её часть. Внедрение водяного знака в программный код подразумевает размещение в нем некоторой скрытой информации, для чего применяются стеганографические подходы.
Под цифровой стеганографией понимается скрытие одной информации в другой. Причем сокрытие это должно реализоваться таким образом, чтобы, во-первых, не были утрачены свойства и некоторая ценность скрываемой информации, а во-вторых, неизбежная модификация информационного носителя, не только не уничтожила смысловые функции, но и на определенном уровне абстракции даже не меняла их. Тем самым факт передачи одного сообщения внутри другого не выявляется традиционными методами.
Носителем
скрытой информации должен выступать
объект, допускающий искажения
Методы стеганографии позволяют не только скрыто передавать данные, но и успешно решать задачи помехоустойчивой аутентификации, защиты информации от несанкционированного копирования, отслеживания распространения информации по сетям связи, поиска информации в мультимедийных базах данных и т.д. Эти обстоятельства позволяют в рамках традиционно существующих информационных потоков или информационной среды решать некоторые важные вопросы защиты информации ряда прикладных отраслей.
Целью
данной работы является создание эффективного
программного обеспечения для внедрения
в исходные тексты программ информации
об авторских правах, что позволит исключить
несанкционированное их использование.
1 Описание методов и средств решения задачи
- Постановка задачи на курсовое проектирование
Задача курсового проекта заключается во внедрении водяных знаков в исходные тексты программ.
Для надежности все данные должны храниться в базе данных для общего доступа по сети, также для более комфортной работы с имеющимися данными.
Программа должна предоставлять пользователю возможность подсчитывать статистические данные использования тех или иных программ на Си. Второй модуль программы должен предоставлять возможность изменять полученные статистические характеристики исходного кода, чтобы появилась возможность идентифицировать автора и таким образом защитить авторские права. Программа должна иметь оптимизированный код, для более быстрой работы. Программа должна иметь оптимизированную структуру базы данных, соответствующей третьей нормальной форме(3NF).
Так
же существуют некоторые основные требования
к использованию СУБД. СУБД должна
иметь высокую скорость работы, высокую
степень защиты информации от несанкционированного
доступа и самое важное - должна
поддерживать язык структурированных
запросов (SQL).
- Общие аспекты проблемы авторского права
Быстрое развитие глобальной сети Интернет обеспечило наличие единой среды передачи информации, доступной практически в любой точке мира. Ключевой проблемой, возникающей при этом, является защита авторского права на передаваемые электронные документы. Авторское произведение в электронном виде наиболее уязвимо в плане неправомерного использования. Электронный документ может быть легко скопирован, обработан, использован при создании других документов, размножен и распространен.
Система авторского права складывалась и развивалась на протяжении многих столетий. За этот срок были выделены ее основные положения, определены отношения между авторами и обществом, меры по защите прав авторов. Однако, в связи с появлением новых направлений творческой деятельности, таких, как создание компьютерных программ, система авторского права не может не претерпеть некоторых изменений. Кроме того, возникает проблема защиты авторских прав на произведения, существующие исключительно в электронном виде, поскольку они обладают некоторыми особенностями, делающими их особенно уязвимыми для несанкционированного использования. Перечислим эти особенности:
- компьютерная информация легко копируется;
- каждая копия идентична оригиналу;
- электронные копии распространяются очень быстро. [1]
Авторское право на произведение возникает в силу факта его создания. Автор или другой обладатель авторских прав оповещает о них, используя знак охраны авторских прав, имя правообладателя и год первого опубликования. В случае представления произведения в виде компьютерной информации (в электронной форме) такое обозначение авторских прав можно удалить без видимых следов. Но автор для закрепления своих прав может, кроме видимого знака, использовать цифровые «водяные знаки» или невидимую метку.
Нанесение
такой метки преследует следующие
цели: она должна четко определять
держателя авторских или
Для надежной защиты метка должна обладать следующими качествами:
- невидимость;
- помехоустойчивость (устойчивость к искажениям);
- защищенность (стойкость к фальсификации).
Когда на изображение ставится видимый логотип держателя прав, он, как правило, располагается в таком месте, где не сможет быть помехой для зрительного восприятия иллюстрации. Следовательно, и его умышленное удаление не повлечет за собой особых нарушений ее структурной целостности. Требование к минимизации искажений предъявляется не только из-за возможного обнаружения метки, но и из чисто эстетических соображений - не имеет смысла маркировать картинку, если ее качество ухудшится настолько, что, она уже будет непохожа на оригинал.
В процессе работы изображение может претерпевать различные трансформации: уменьшаться или увеличиваться, преобразовываться в другой формат и т.д. Кроме того, оно может быть сжато, в том числе и с использованием алгоритмов сжатия с потерей данных. Неизменность метки в условиях подобных преобразований достижима только в случае, когда она помещается в обширных областях по всей площади изображения.
Если
метка должна быть устойчивой к различного
вида помехам и трансформациям, следовательно,
она должна быть устойчива к действиям,
направленным на ее удаление.[1]
- Современные методы защиты программного обеспечения
Разработчики
программных продуктов, получающие
доход от их продажи, постоянно сталкиваются
с рядом проблем, связанных с нелегальным
копированием программного обеспечения.
Лица, нарушающие авторские права, могут
создать копию продукта для частного использования,
осуществления промышленного шпионажа
путем обратного проектирования программы
и последующей ее продажи как своей собственной
с целью получения выгоды. Каждое из перечисленных
действий злоумышленника несёт для разработчика
потерю части дохода от разработки. Для
решения этой проблемы параллельно с развитием
технологий создания программного обеспечения
(ПО) совершенствуются технологии защиты
программ от несанкционированного использования.
[2]
Маскирующие преобразования программ
Защита ПО от нелегального использования его отдельных функциональных модулей в последние годы все более чаще достигается путем обфусцирования (obfuscation) исходного кода. Под обфусцированием понимается преобразование кода программы так, что бы максимально затруднить процесс декомпиляции и анализа кода с целью восстановления реализованных в нем алгоритмов.
Одним из способов такой защиты является маскировка программ, заключающаяся в применении к исходному тексту программы цепочки маскирующих преобразований, то есть преобразований, сохраняющих реализуемую программой функцию (являющихся функционально эквивалентными), но затрудняющих понимание этой функции.
Все
маскирующие преобразования делятся
на текстуальные преобразования, преобразования
управляющей структуры и
В
группе текстуальных маскирующих преобразований
рассматриваются преобразования удаления
комментариев, переформатирования текста
программы и изменения
Int fib(int n)
{
int a, b, c;
a = 1;
b = 1;
if (n <= 1) return 1;
for (; n > 1; n--) {
c = a + b;
a = b;
b = c;
}
return c;
}
Рисунок 1 – Исходная программа
int fib(int n)
{
int a, b, c, i;
long long t;
a = 1;
b = 1;
if (n <= 1) return 1;
while (1) {
t = n * n % 65537;
for (i = 0; i < 15; i++)
t = t * t % 65537;
if (n * t <= 1) break;
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
Рисунок
2 – Обфусцированная программа
Другое маскирующее преобразование - введение непрозрачных предикатов - является ключевым для повышения устойчивости других маскирующих преобразований, например, внесения недостижимого кода. Непрозрачным предикатом называется предикат, всегда принимающий единственное значение true или false. При маскировке программы предикат строится таким образом, что его значение известно, но установить по тексту замаскированной программы, является ли некоторый предикат непрозрачным, трудно.
Лексические преобразования. Этот вид затемняющих преобразований является самым простым и в то же время обеспечивающим наименьшую защиту. Действие лексических преобразований распространяется только на лексическую структуру программы, т.е. фактически сводится к переименованию идентификаторов (переменных, классов, методов), затрудняя, таким образом, анализ логики программы на основании имен этих идентификаторов.
Основной сферой применения лексических преобразований являются интерпретируемые языки программирования исходные программы на которых компилируются не в машинный код, а в байт-код – машинно-независимый псевдоязык, понятный интерпретатору языка. Обычно байт-код содержит информацию об исходном коде (имена идентификаторов, названия классов и т.п.), поэтому вопрос скрытия такой информации является существенным для интерпретируемых языков. Пример лексического преобразования показан на рисунках 1 и 2. На рисунке 1 приведен оригинальный код программы, на втором – код той же программы после лексического затемнения.
Лексические преобразования предотвращают некоторое количество попыток воровства интеллектуальной собственности, однако не создают серьезного препятствия для опытного реверс-инженера.
Преобразования хода выполнения. Второй тип затемняющих преобразований оперирует с процессом выполнения программы, т.е. субъектом преобразований являются последовательности вызовов функций (операторов).
Коллберг
предложил несколько
Существует достаточно большое количество преобразований процесса выполнения, похожих на показанные на рисунке 4. Устойчивость таких преобразований напрямую зависит от устойчивости непроницаемых предикатов, на которые они опираются. Таким образом, очень важно уметь конструировать устойчивые непроницаемые предикаты, важными критериями выбора которых является их незаметность и низкая стоимость.
При выборе непроницаемых предикатов логично исходить из проблем, с которыми сталкиваются автоматизированные системы, проводящие анализ затемненного кода. Так, большинство таких систем используют методы, основанные на статическом анализе. Принимая во внимание факт, что точный статический анализ структур, основанных на указателях и параллельных регионах, является достаточно затруднительным, эти структуры можно использовать в качестве непроницаемых предикатов.
В качестве примера сильных непроницаемых предикатов можно привести предикаты на основе псевдонимов. Основной идеей этого метода является добавление в программу кода, который строит множество сложных динамических структур. Множество глобальных указателей ссылаются на вершины внутри этих структур. Вышеуказанные структуры в ходе выполнения программы будут случайным образом обновляться (будут изменяться внутренние указатели, добавляться и удаляться вершины и т.п.), но некоторые условия будут поддерживаться в неизменном состоянии. Примерами таких условий могут быть «указатели p и q никогда не будут указывать на один и тот же элемент в куче», «существует путь от p до q» и т.п. Впоследствии эти условия будут использоваться для генерации непроницаемых предикатов.
Определение графа логики программы извне – достаточно простая операция, линейно зависящая от количества простых блоков в программе. По вырожденному же графу достаточно сложно определить ход работы программы. [3]
Вырождение
графа логики проходит в два этапа.
На первом этапе высокоуровневые
структуры (например, циклы) преобразуются
в эквивалентные if-then-goto-
На втором этапе операторы goto, появившиеся в результате первого этапа, модифицируются таким образом, что цели этих операторов goto определяются динамически. Пример второго этапа приведен на рисунке 5.
Рисунок
5 – Пример второго этапа
Преобразования данных. Третьим типом затемняющих преобразований является затемнение данных. Наиболее распространенным преобразованием является разделение переменной – представление атомарного значения (например, целого или булевого) в виде некоторой сложной структуры данных. На рисунке 6 показана реализация операции логического И.
На рисунке 6 показано разделение трех булевых переменных A, B и C на короткие целые переменные а1, а2, b1, b2, c1, c2 соответственно. Интересным аспектом выбранной интерпретации является возможность вычислить одно значение несколькими способами. Например, операторы (2’) и (3’) отличаются друг от друга, однако оба присваивают переменной значение False. [3]
Рисунок
6 – Разделение трех булевых переменных
Шифрование кода. Отдельным случаем затемнения являются методы, реализующие шифрование программного кода (как всего кода программы, так и отдельных его участков). Эти методы используются в основном для затемнения выполняемого машинного (не интерпретируемого) кода.
Ключ для шифрования (и соответственно расшифрования) кода должен быть надежно защищен. В идеале, он должен отличаться для каждого пользователя программы. Однако такой подход является неприемлемым для продуктов с большим количеством пользователей, поскольку предполагает, что каждому пользователю будет выдаваться отдельная копия продукта, зашифрованная ключом этого пользователя. Поэтому более удобным вариантом является использование общего ключа и его хранение в недоступном месте (например, на смарт-карте или сервере приложений). Еще одним подходом к хранению ключа является его генерация в ходе выполнения программы, однако такой подход более уязвим к реверс-инженерии.
Можно выделить два подхода к расшифровке выполняемого кода: расшифровка всего кода при запуске программы и поэтапная расшифровка необходимых участков кода непосредственно перед их выполнением с последующей обратной зашифровкой. Слабостью первого подхода является возможность снять копию участка памяти, содержащего расшифрованную программу, поэтому этот подход крайне ненадежен. Для того чтобы получить программу в незашифрованном виде, атакующему нужно выполнить все зашифрованные фрагменты, для каждого фрагмента снимая дамп памяти. При большом количестве зашифрованных фрагментов эта задача становится практически невыполнимой.
Шифрование программного кода также может применяться и для защиты кода от модификации. При шифровании некоторого участка кода совместно с данными этого участка кода можно поместить контрольную сумму его байт. Таким образом, если злоумышленник внесет изменения в шифртекст (например, с экспериментальной целью), контрольная сумма при расшифровке не совпадет с оригинальной и эти изменения можно будет отследить.
Определенный интерес представляет метод на основании саморасшифровывающегося кода. Данный метод не предполагает наличия некоторого фиксированного ключа. Программный код разбивается на участки, которые шифруются независимо друг от друга. В процессе выполнения программы каждый следующий участок расшифровывается ключом, полученным применением некоторой функции к байтам предыдущего. Очевидно, что этот метод не предоставляет защиты от неавторизованного выполнения кода, а только от реверс-инженерии и модификации выполняемого кода. [3]