|
|
Borland Delphi >Статьи
Защита программ от взлома
Эта статья посвящена достаточно актуальной в
настоящее время тематике - защите программ от взлома и нелегального
копирования. Этой теме посвящено много статей, одна из наиболее
интересных (из тех, которые попались мне) - статья "Защита
shareware-программ" Владимира Каталова в Компьютерре Online#240. Он
привел ряд советов по написанию shareware программ и я не хочу
повторяться - сходите, почитайте.
Рассмотрим некоторые тонкости организации
защиты на достаточно популярном примере - предполагаем, что программа
защищена некоторым кодом (серийным номером, паролем), который сообщается
пользователю после соблюдения им определенных условий. До регистрации в
этой программе заблокирован ряд каких либо полезных функций,
используется надоедливая реклама или ограничен строк работы. После ввода
этого кода производится его проверка и при положительном исходе проверки
программа начинает нормально работать. По неизвестной мне причине в
большинстве современных программ данная защита сделана однообразно и для
ее снятия необходимо 10-15 минут. В этой статье я постараюсь поделиться
опытом в построении систем защиты. Могу сразу предупредить - хорошему
хакеру противостоять практически бесполезно, да и не нужно - при желании
любая защита может быть взломана, это вопрос времени.
Инструментарий хакера. Современный хакер имеет в
своем арсенале набор разнообразных утилит для взлома. Их можно
подразделить на несколько категорий
-
Отладчики. Позволяют прерывать
выполнение программы при достижении заранее заданных условий,
производить пошаговое выполнение программы, изменять содержимое памяти
и регистров и т.п. . Наиболее популярным, удобным и мощным является
отладчик SoftICE, который при достаточно примитивном интерфейсе
обладает приличными возможностями и весьма стабильно работает.
-
Дизассемблеры. Производят
дизассемблирование программы для дальнейшего изучения полученного
кода. Один из наиболее популярных - IDA. От дизассемблера достаточно
легко защититься - зашифровать или заархивировать программу. Тогда
дизассемблируется только архиватор или кодировщик.
-
Средства мониторинга. Это набор
утилит, отслеживающих операции с файлами, реестром, портами и сетью.
-
Средства пассивного анализа программы.
Показывают разную информацию о программе - извлекают ресурсы,
показывают связи, используемые библиотеки. Классический пример -
утилита DEPENDS.EXE из комплекта Visual Studio. Она показывает, какие
библиотеки используются программой и какие функции импортируются.
-
Прочие утилиты. Их великое
множество (можно найти на диске типа "Все для хакера", причем в
изобилии). Это разнообразные редакторы, анализаторы ...
Наиболее популярны следующие программы
мониторинга :
FileMon - утилита, позволяющая вести
мониторинг всех операций с файлами. Имеет удобный фильтр, может
сохранять отчет в файле. Поэтому нет смысла делать "секретные" файлы
где-нибудь в Windows/System - их элементарно найти.
RegMon - аналог FileMon, только
ведется мониторинг всех операций с реестром. Аналогично файлам,
бессмысленно создавать в реестре "секретные" ключи - они сразу бросаются
в глаза.
PortMon - мониторинг работы с портами
ввода/вывода
TCP_VIEW - монитор соединений по
TCP-IP
RegUtils - набор утилит для контроля
за реестром - делает копии реестра, позволяет сравнивать копии и
просматривать изменения.
Утилиты типа FileMon могут резко упростить
взлом программы - легко определить место, в котором программа обращается
к указанному файлу или ключу реестра.
Основы построения защиты - шаг за шагом
Как ввести регистрационный код. Ввод пароля или
регистрационного номера является ответственным делом - хакер постарается
отловить адрес памяти, в который будет записан пароль. Затем на
обращение по этому адресу ставится точка останова (команда BPM в
SoftICE), что позволяет поймать начало процедуры проверки
регистрационного кода. Если для ввода используются стандартные элементы
ввода Windows, то алгоритм действий хакера можно формализовать и
выглядит он примерно так:
-
Устанавливает точку останова на считывание
текста из стандартного элемента ввода (функции GetWindowText,
GetGlgItemText модуля KERNEL32)
-
При вызове этой функции анализируем ее
параметры и таким образом определяем, по какому адресу будет размещено
считываемое значение и ставим обращение к этой области памяти точку
останова. А достоверности определенного адреса легко убедиться - после
выполнения функции там появится введенная строка
-
При срабатывании этой точки останова мы
попадаем в анализатор введенного значения и либо делаем генератор
регистрационных ключей, либо ломаем процедуру проверки. И то, и другое
весьма просто сделать - достаточно только изучить ассемблер и API
Набор этих действий стандартен и мне не раз
попадались подробные руководства типа "Взлом Windows программ - шаг за
шагом", ориентированные на продвинутого пользователя.
Рассмотри несколько решений, которые могут
затруднить взлом на этом этапе.
Совет _0. Старайтесь как можно меньше
применять стандартные функции (особенно API-шные) и компоненты VCL. Так
что Assembler, Assembler и еще раз Assembler ...
Сущность этого совета надеюсь очевидна -
современные дизассемблеры умеют распознавать стандартные процедуры
высокоуровневых языков, а API - вообще отдельный разговор - SoftICE
обладает изумительной возможностью - загружать символьные имена для
любых указанных библиотек (особенно для KERNEL32.DLL) - отладка резко
упрощается, т.к. мы видим имена вызываемых функций и можем ставить точки
останова на вызов функций по их имени.
Совет _1. Применяйте нестандартный способ
ввода пароля.
Наипростейший путь - написать свой
визуальный компонент для ввода регистрационного кода. Он конечно должен
будет обрабатывать события от клавиатуры, но момент считывания кода
нельзя поймать избитыми методами. Это уже что-то, но есть второй способ
взлома, основанный на поиске введенного кода в памяти. Для этого в
SoftICE есть удобная команда "S стартовый адрес L длина 'образец'" ,
которая позволяет найти введенное значение в памяти.
Совет _2. Не храните введенный код в
одном месте !
Совет _3. Не храните введенный код
открытым текстом !
Итак, что же следует сделать. Для начала
необходимо завести в программе 5-10 переменных типа STRING и после ввода
кода переписать введенное значение в них. Делать это лучше всего не в
одном месте, а распределить по программе. Таким образом поиск даст кучу
адресов, по которым будет находиться введенный код. Я в таком случае
поступаю так - по таймеру создаю в динамической памяти новую строковую
переменную, пишу в нее код. Затем на следующем срабатывании таймера
создаю новую переменную, переписываю в нее код, а старую уничтожаю. При
определенном навыке можно заполонить память значениями введенного кода и
сделать поиск почти бесполезным. Причем такое копирование можно
совместить с проверкой кода или эмуляцией этой проверки. Затем с эти
строками неплохо поделать какие-либо операции - сравнить с чем-нибудь
...
Советы 3 и 1 можно объединить - создать свой
компонент, который позволит вводить код нестандартным способом с его
одновременной шифровкой.
Анализ регистрационного кода. Итак,
код введен и приняты меры для того, чтобы его было непросто найти (хотя
найти то его можно, но это время, навык ...). Теперь следующий шаг -
анализ. Поэтому сразу совет:
Совет _4. Ни в коем случае не
анализируйте код сразу после его ввода.
Чем дальше ввод кода от его анализа, тем
лучше. Самое разумное - после ввода кода поблагодарить пользователя за
сотрудничество и сообщить, что со временем будет выполнена регистрация
программы. А анализ кода произвести, например, через 1-2 минуты в
совершенно другом месте программы.
Совет _5. Не проверяйте код только в
одном месте и не пишите для проверки функцию.
Достаточно найти и отключить эту проверку, и
защита взломана. Если проверок несколько, они разные и распределены по
программе, то взлом затрудняется.
Совет _6. Не проверяйте пароль одним
алгоритмом.
Рекомендуется разработать 2-3 алгоритма
проверки, например 1-2 цифры должны делиться на 3, а 3-7 наложенные по
какому-либо алгоритму на имя пользователя должны дать в сумме 4. Эти две
проверки осуществляем в различных местах с достаточно большим временным
разносом - взломав первый метод хакер не будет догадываться о
существовании еще нескольких, которые проявятся со временем.
Совет _7. Ни в коем случае не
предпринимайте никаких действий после проверки. По неизвестной
причине большинство программ выглядят примерно так
IF NOT(SuperRegCodeCheck) then
Begin
ShowMessage('Неверный код, дальнейшая работа невозможна');
halt;
end;
В примере некая процедура проверяет код и
при несовпадении предпринимает активные действия, которые буквально
кричат "вот она где защита !!". Наилучший шаг - выждать день -два (или
хотя бы минут 15). Причем все действия по проверке следует как можно
дальше отнести от выдачи сообщений и прочих действий, предпринимаемых
при обнаружении неправильного кода.
Совет _8. Отвлекающие маневры.
Кроме реальных функций проверки кода очень
неплохо сделать пару бутафорских - они будут вызываться после ввода
кода, проводить активные манипуляции с введенным значением, выдавать
сообщения о некорректности введенного кода ... - т.е. отвлекать внимание
от реальной проверки.
Совет _9. Не храните результатов проверки
в переменной и не используйте ее для явного ограничения функций
незарегистрированной программы.
Классический пример нарушения этого правила
IF NOT(LegalCopy) then
ShowMessage('Сохранение работает только в зарегистрированной версии')
else
SaveFile;
Таким образом элементарный анализ
показывает, что переменная LegalCopy хранит результат проверки и
поставив на нее точку останова можно выловить саму проверку.
Отредактировав это значения в памяти можно временно сделать копию
"зарегистрированной",а установка точки останова на изменение этой
переменной выведет на место ее проверки. Да и взлом сводится к тому, что
функция проверки кода урезается до двух команд ассемблера:
MOV [адрес LegalCopy], 1
RET
Совет _10. (вытекает из 9) Не храните
результатов проверки на диске или в реестре.
Типичная ошибка - выяснили, что копия
зарегистрирована и сделали где-нибудь метку. Отловить это достаточно
просто (см. описание REGMON и FILEMON). Наилучший способ - сохранить
пароль и имя пользователя в том виде, в котором он их ввел. Затем при
каждом запуске программы проверять корректность этого кода, но не
забывая Совет _11. Ничего не проверяйте сразу при запуске приложения
или сразу после считывания сохраненного имени или кода. Помните, что
считывание кода и его ввод в окне регистрации идентичны по мерам защиты
- дублирование в разных областях памяти, шифрование ...
Выводы: мы устроим проверку кода в
нескольких местах программы, при этом применим несколько алгоритмов
проверки, не будем использовать API.Кроме того, стоит проделать
несколько отвлекающих маневров.
Общие советы по защите программ
-
CRC - контрольные суммы. Любой файл,
строку или блок данных можно защитить контрольной суммой, которую
затем можно рассчитать и сравнить с эталоном. При сравнении с эталоном
конечно следует весть осторожно - см. первые 11 советов. Итак,
совет 12. Защищайте программы и данные контрольными суммами. Это
поможет не только от взлома, но и защитит программы от вируса или
внедрения троянца.
-
Применяйте шифровку программ и данных.
Очень неплохо сжать программу и данные. Я, например, разработал свой
собственный архиватор - RAR-у и ZIP-у он конкуренции не составит, но
сжатые им данные разжать очень непросто, придется изрядно повозиться.
Да и изменить их проблематично - придется разжать, изменить и сжать.
-
Отлов пошаговой отладки программы.
Существует много способов, я в свое время провел целое исследование
этого вопроса под DOS, насобирал и придумал не менее 20 методов, но
они мало приемлемы под Windows. Самый простой и надежный способ -
таймер. При работе программы периодически фиксируем системное время и
рассчитываем время работы фрагментов кода между ними. И если 200-400
команд процессора работают 2-3 минуты, то тут есть над чем задуматься.
Совет 13. Не определяйте дату и время
стандартными способом !! Придумайте что-нибудь оригинальное.
Совет 14.Не стоит хранить что-либо секретное
в файлах или реестре. Работа с файлами или реестром может быть
детально запротоколирована и проанализирована, и все тайное станет
явным.
Совет 15.Не храните ничего важного
открытым текстом, особенно сообщения типа "Это незарегистрированная
версия ...", "Введенный пароль не верен ...".
Они для хакера - как для быка красная тряпка, и действительно - находим
такое сообщение, ставим точку останова на обращение к участку памяти с
этим сообщением и получаем возможность поймать момент выдачи этого
сообщения.
Советы по созданию меток для организации
ограничения по времени
Защита "ограничение времени работы" состоит
в том, что программа каким образом фиксирует момент своего первого
запуска и работает установленное время (обычно 20-30 дней). После
истечения этого срока программа отказывается запускаться. Как проверить
текущую дату я уже где-то тут писал - нестандартным способом, например
по дате на файлах реестра или свежесозданном своем файле. Весь фокус в
другом - как зафиксировать на компьютере дату первого запуска
(естественно так, чтобы изничтожение программы и ее повторная установка
не давали эффекта). Использование "секретных" файлов в системных папках
или изменения в существующих файлах легко отловить при помощи FILEMON.
Реестр то же отпадает из-за REGMON. Прочие методы (типа записи в ВООТ
сектор ...) тоже неприемлемы - не те времена, по Windows все это не
пройдет. Наиболее оригинально (на мой взгляд) прошить дату в саму
программу и постоянно обновлять ее на своем сайте (естественно,
автоматически). Таким образом отсчет неявно идет от момента скачивания
программы с сайта. Есть тут правда и минус - после завершения срока
можно повторно скачать эту программу и получить еще 15-20 дней ... . С
другой стороны это оригинально - пользователю рано или поздно надоест
скачивать эту программу и он или откажется от нее, или купит. Но при
этом стоит помнить, что программу можно скачать несколько раз и сравнить
варианты, выявив, где лежит дата. Поэтому стоит позаботиться о том,
чтобы изменился почти весь файл (например, изменить пару опций
компилятора)
Советы по формированию регистрационных
кодов
Формирование кодов может вестись по
следующим основным направлениям:
-
Жестко фиксированные коды, прошитые в
программу. Их обычно немного и их огласка сводит защиту к нулю.
-
Некий алгоритм проверки кода. Немного
лучше первого, но лишь немного. Возьмите за пример код Windows - его
знает любой пользователь
-
Алгоритм проверки кода, использующий имя
пользователя. Очевидно, что для каждого имени будет уникальный номер
(или номера - их может быть несколько, в зависимости от алгоритма).
Это уже лучше, но нелегальное распространение держится на эгоизме
зарегистрированных пользователей - ничто не мешает им предать
имя/пароль огласке, но тогда хотя бы можно вычислить виновника и
заблокировать его код
-
Алгоритм проверки кода, использующий имя
пользователя и некоторые уникальные или динамически изменяющиеся
параметры, например информацию о компьютере. Это надежно, дает
привязку к компьютеру, но в наш век постоянных апгрейдов очень
неудобен.
-
On-Line регистрация. Состоит в том, что
программа в On-Line связывается с сайтом разработчиков (или компании,
осуществляющей продужу софта) и передает туда ревизиты пользователя. В
ответ программе передается регистрационная информация. Этот метод
может и хорош для ряда программ, но на мой взгляд не выдерживает
никакой критики по двум соображениям:
1. Никто не может гарантировать, что конкретно передаст программа в
Инет. А передать она может все, что угодно - параметры компьютера,
пароли, любые данные и т.п.
2. Конкретный пользователь ножет не иметь доступа к Инет. Это особенно
важно для программ, работа которых не связана напрямую с Сетью. И
зарегистрировать такую программу его практически никто к себе на
компьютер не пустит (из соображений п.п. 1)
Рекомендовать тут что-либо бесполезно, но я
например использую разновидности метода 3.
|