Конспект лекцій до дисципліни Безпека програм та даних

Вид материалаКонспект

Содержание


Инструментарий хакера
Основы построения защиты - шаг за шагом
Совет _0. Старайтесь как можно меньше применять стандартные функции (особенно API-шные) и компоненты VCL. Так что Assembler, Ass
Совет 1. Применяйте нестандартный способ ввода пароля.
Совет 2. Не храните введенный код в одном месте !
Совет 3. Не храните введенный код открытым текстом !
Анализ регистрационного кода.
Совет 4. Ни в коем случае не анализируйте код сразу после его ввода
Совет 5. Не проверяйте код только в одном месте и не пишите для проверки функцию.
Совет 6. Не проверяйте пароль одним алгоритмом.
Совет 7. Ни в коем случае не предпринимайте никаких действий после проверки.
Совет 8. Отвлекающие маневры.
Совет 9. Не храните результатов проверки в переменной и не используйте ее для явного ограничения функций незарегистрированной пр
Совет 10. (вытекает из 9) Не храните результатов проверки на диске или в реестре.
Общие советы по защите программ
Совет 13. Не определяйте дату и время стандартными способом !!
Совет 15.Не храните ничего важного открытым текстом, особенно сообщения типа "Это незарегистрированная версия ...", "Введенный п
Советы по созданию меток для организации ограничения по времени
Советы по формированию регистрационных кодов
Что и как закрывать
...
Полное содержание
Подобный материал:
1   2   3   4   5   6   7

Инструментарий хакера


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

Их можно подразделить на несколько категорий
  • Отладчики. Позволяют прерывать выполнение программы при достижении заранее заданных условий, производить пошаговое выполнение программы, изменять содержимое памяти и регистров и т.п. Наиболее популярным, удобным и мощным является отладчик SoftICE, который при достаточно примитивном интерфейсе обладает приличными возможностями и весьма стабильно работает.
  • Дизассемблеры. Производят дизассемблирование программы для дальнейшего изучения полученного кода. Один из наиболее мощных и популярных - IDA. От дизассемблера достаточно легко защититься - зашифровать или заархивировать программу. Тогда дизассемблируется только архиватор или кодировщик. Однако тот-же IDA имеет мощный встроенный скриптовой язык, позволяющий производить расшифровку программы
  • Средства мониторинга. Это набор утилит, отслеживающих операции с файлами, реестром, портами и сетью.
  • Средства пассивного анализа программы. Показывают разную информацию о программе - извлекают ресурсы, показывают связи, используемые библиотеки. Классический пример - утилита DEPENDS.EXE из комплекта Visual Studio. Она показывает, какие библиотеки используются программой и какие функции импортируются.
  • Прочие утилиты. Их великое множество (можно найти на диске типа "Все для хакера", причем в изобилии). Это разнообразные редакторы, анализаторы ...

Наиболее популярны следующие программы мониторинга :
  • FileMon - утилита, позволяющая вести мониторинг всех операций с файлами. Имеет удобный фильтр, может сохранять отчет в файле. Поэтому нет смысла делать "секретные" файлы где-нибудь в Windows/System - их элементарно найти.
  • RegMon - аналог FileMon, только ведется мониторинг всех операций с реестром. Аналогично файлам, бессмысленно создавать в реестре "секретные" ключи - они сразу бросаются в глаза.
  • PortMon - мониторинг работы с портами ввода/вывода
  • TCP_VIEW - монитор соединений по TCP-IP
  • RegUtils - набор утилит для контроля за реестром - делает копии реестра, позволяет сравнивать копии и просматривать изменения.

Утилиты типа FileMon могут резко упростить взлом программы - легко определить место, в котором программа обращается к указанному файлу или ключу реестра.

Основы построения защиты - шаг за шагом


Как ввести регистрационный код. Ввод пароля или регистрационного номера является ответственным делом - хакер постарается отловить адрес памяти, в который будет записан пароль. Затем на обращение по этому адресу ставится точка останова (команда BPM в SoftICE), что позволяет поймать начало процедуры проверки регистрационного кода. Если для ввода используются стандартные элементы ввода Windows, то алгоритм действий хакера можно формализовать и выглядит он примерно так:
  1. Устанавливает точку останова на считывание текста из стандартного элемента ввода (функции GetWindowText, GetGlgItemText модуля KERNEL32)
  2. При вызове этой функции анализируем ее параметры и таким образом определяем, по какому адресу будет размещено считываемое значение и ставим обращение к этой области памяти точку останова. А достоверности определенного адреса легко убедиться - после выполнения функции там появится введенная строка
  3. При срабатывании этой точки останова мы попадаем в анализатор введенного значения и либо делаем генератор регистрационных ключей, либо ломаем процедуру проверки. И то, и другое весьма просто сделать - достаточно только изучить ассемблер и 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.


Что и как закрывать

Если вы решили распространять свой продукт как shareware, то наверняка уже продумали различия между незарегистрированной и зарегистрированной версией. Если еще нет, то могу подсказать: в принципе, можно использовать три подхода - демо-версия, time limited-версия и ограниченная версия (вообще-то, можно еще делать упор на совесть и просто просить прислать вам деньги, если программа понравилась, но это, к сожалению, работает далеко не всегда: по моему опыту, у пользователя должен быть стимул, побуждающий к регистрации, причем реальный, а не просто условия лицензионного соглашения).

С демо-версиями все просто. В двух словах, принцип такой: вы сильно урезаете возможности программы, попросту "выкидывая" части кода из исходного текста, перекомпилируете и выкладываете результат как демо-версию. (Тем же, кто изъявляет желание поощрить вас материально, вы просто посылаете полную версию программы, или сообщаете, где ее можно взять, - указав, например, "скрытую" ссылку на вашей странице.) Оговорюсь сразу, что этот способ - худший из всех. Во-первых, по демо-версии пользователь не всегда может понять, насколько программа ему подходит. Во-вторых, один из оплативших может подложить вам свинью и рассказать другим, где можно поживиться полной версией "на халяву" (или просто начать раздавать ее всем своим знакомым), - все равно у вас нет способа узнать, кто же сделал "доброе" дело… А если вы будете посылать полную версию обычной (или даже электронной) почтой, то у вас резко увеличатся накладные расходы.

Второй способ более приемлем, но труднее реализуем (почему - объясню позже). Принцип состоит в том, что вы предоставляете пользователю право тестировать ваше творение "по полной программе", но только в течение некоторого ограниченного срока: скажем, тридцати дней с момента установки на компьютер или с момента первого запуска. Или как вариант: ограничение на число запусков. По истечении отведенного срока (или после заданного числа запусков) программа просто перестает работать или переходит в демо-режим.

Третий, самый распространенный способ: некоторые функции в вашей программе остаются "закрытыми", пока она не будет оплачена. Можно, например, ограничить размер файлов, с которыми приложение может работать (установив некую "верхнюю планку"), или не давать сохранять результаты работы, или отключить некоторые "продвинутые" возможности - тут уж кому как нравится. После оплаты вы посылаете пользователю некий пароль (ключ, регистрационный номер и т. п.), который, будучи введенным, разблокирует ранее недоступные функции.

Да, кстати, не помешает еще и такая вещь, как reminder (или "nag screen", как угодно). Это совсем просто: при запуске программа определяет, зарегистрирована она или нет; в последнем случае пользователю ненавязчиво напоминают, что не худо бы и честь знать, то есть заплатить.

Как это сделать

Можно, конечно, воспользоваться услугами третьих фирм - просто купить программный пакет, обеспечивающий переход от незарегистрированной версии к зарегистрированной после оплаты и ввода некоторого пароля (см., например, ссылка скрыта или ссылка скрыта). Проблема в том, что если эту систему купило хотя бы несколько разработчиков и защищенные таким способом продукты уже имеются, то можете быть уверены, что в этой защите уже кто-нибудь "поковырялся" и используемые в ней трюки давно всем известны. Так что придется вам потрудиться самому.

Демо-версии я рассматривать здесь не буду - и так все ясно (см. выше). Можно, конечно, распространять и их, но только как дополнение к "оценочной" версии, - например, раздавать на выставках, договориться о включении на различные CD-ROM и т. п. - исключительно в целях рекламы.

С ограничением по времени немного сложнее. При инсталляции (или при первом запуске) программа должна где-то запомнить текущую дату (или проинициализировать счетчик запусков), а при последующих запусках - сверять даты (не кончился ли "испытательный срок") или увеличивать счетчик и проверять его значение. Если вы действительно знаете это место (куда писать дату/счетчик) - возьмите с полки пирожок (подробнее о ваших супертайниках - см. ниже).

Частично работоспособная версия - по моему мнению, наиболее правильный выбор. Наверняка в вашей программе есть возможности, которые можно назвать "профессиональными" (для продвинутых пользователей). Или просто приятные мелочи, которые можно описать коротким и звучным словом "cool", то есть те, жить без которых можно, но неудобно. Кстати, это еще и очень хороший стимул к покупке: хочешь сделать свою работу более приятной и легкой - покупай!

Теперь о том, что должно происходить после оплаты. Здесь опять же есть две дороги: "статические" пароли и генератор ключей.

В первом случае программа "разблокируется" при вводе пароля, соответствующего некоторым критериям. При этом сам пароль не является индивидуальным. Я думаю, что уже ни для кого не является секретом, как это сделала компания Microsoft со своими CD-keys: сумма цифр должна делиться на 7. Проще некуда. Естественно, вы можете придумать что-нибудь посложнее, например, делать некие вычисления, которые должны приводить к определенному результату. Как вариант - можно хранить все правильные ключи внутри самой программы.

Поскольку каждому пользователю вы будете посылать свой пароль (хотя и не связанный с его данными), то в случае, если один из них будет опубликован для "широкого использования", вам нетрудно будет вычислить обидчика.

Что касается генератора ключей, то это более элегантный способ: зная имя пользователя, вы можете путем каких-либо преобразований сгенерировать из него некий ключ. Тут уж включайте свою фантазию: лучше всего, если преобразование будет односторонним и достаточно запутанным.

Нельзя не упомянуть и еще об одном способе защиты - с помощью аппаратных ключей, подключаемых к параллельному порту компьютера (типа HASP). Конечно, для программы стоимостью пять долларов это не очень подходит (слишком дорого; не все любят; с некоторыми устройствами не достигается полная совместимость и т. д.), но тем не менее… Можете попробовать.

Маленький сюрприз

Если ваша программа действительно хороша, то через два-три дня после ее выпуска вас ждет сюрприз: в Интернете появится "халявный" регистрационный код, или crack, или patch, или взломанная версия. Кстати, если вам не знакомы эти термины, то вот как их можно определить (взято из news:alt.cracks): "Crack: Any method used to defeat protection applied to a software program to allow its full unencumbered use without paying the author for it. Patch: An executable software program that, when aimed at another software program, modifies the target program for some specific purpose". В общем, идея ясна: вашей программой теперь могут пользоваться все желающие, причем платить для этого совсем не обязательно.

Конечно, вы можете об этом и не узнать, если привыкли экономить на доступе к Интернету и/или если не знаете, где искать, но я вас уверяю - если программа интересна не только вам и вашим друзьям, то ее обязательно сломают. Сто процентов.

Должен вас огорчить (или обрадовать?): 99% процентов защит, применяемых в shareware-программах, ломаются за 10-15 минут. Для этого даже не надо быть хакером. Все, что требуется, - это несколько программ: мощный отладчик типа SoftICE, дизассемблер типа IDA плюс пара утилит типа FileMon, RegMon, VxdMon. Иногда даже этого много. Ну и еще, конечно, хотя бы базовое знание ассемблера.

Я не буду здесь углубляться в детали "взлома" - в Интернете существует множество прекрасно написанных пособий как для "начинающих", так и для "продвинутых" хакеров. Остановлюсь лишь на самых общих принципах (должен сразу оговориться, что сам я взломом никогда не занимался и заниматься не собираюсь - кроме как для развлечения; если программа мне нравится, я регистрирую ее легальным способом). Очень надеюсь, что борцы с пиратством не расценят это как "курс молодого бойца" для желающих попробовать свои силы…

Итак… Обычно регистрация выглядит следующим образом: пользователь нажимает на кнопку "Зарегистрировать!" (или обращается к соответствующему пункту меню), и перед ним появляется окошко с предложением ввести регистрационный ключ. При закрытии этого окошка (после ввода ключа) происходит верификация. Верификация может быть ужасно сложной и запутанной, но в конце концов она приходит к закономерному результату, а именно операции сравнения (введенного ключа с правильным или вычисленного значения с некоторым образцом) или записи в стек (или регистр) результата верификации.

Все до гениальности просто: все операции работы со строками (если вы пишете на языке высокого уровня) используют вызовы соответствующих функций (API) ядра Windows (kernel) или обращения к Run-Time Library. И те и другие легко отслеживаются отладчиком, а зачастую и распознаются дизассемблером… Если же вы использовали генератор ключей, то рано или поздно в памяти появится "правильная" строка - то есть та, которая должна быть, если пользователь честно оплатил нелегкий труд программиста. Поэтому чаще всего хакер имеет возможность зарегистрировать программу "на себя" и раздать пароль всем желающим (так, например, было сделано с прекрасным антивирусом AVP от очень уважаемого мною Евгения Касперского).

Кто такой (точнее, такие) PhrozenCrew, вы, наверное, знаете, а если (пока) не знаете, то в двух словах: это самая большая (хотя и не самая старая) "крэкерская" группа, занимающаяся взломом shareware-программ (на их счету более трех тысяч "пострадавших" авторов); насчитывает около сорока активных членов, включая основателя (The Keyboard Caper, родом из Южной Африки), президента и вице-президента (Archimede и TeRaPhY, соответственно), собственно "крэкеров", курьеров, тестировщиков и пр. Впрочем, это уже тема для отдельной статьи…

В случае, если подобрать пароль невозможно ("шароварщики" все-таки тоже не лыком шиты и обычно имеют понятие об ассемблере), используется другой подход: возвращаемое проверочной функцией значение просто заменяется на противоположное (и всего делов-то - заменить безусловный переход на условный или наоборот). А дальше пишется малюсенькая программа, которая делает то же самое, но уже не в памяти, а напрямую в EXE-файле вашей любимой программы…

Если ваша программа - time-limited, то здесь все еще проще (ну прямо как в старом анекдоте про невезучего еврея - или акула попадется глухая, или свисток для отпугивания будет сломанный :). Дело в том, что время первого запуска надо где-то хранить (при этом оставляя неизменным при переинсталляциях). Хранить можно только в двух местах: в Registry или в файле на диске (варианты типа неиспользуемых дорожек я с негодованием отметаю - ребята, это же вам не DOS, сами же намучаетесь, а то и конечному пользователю диск испоганите). С помощью упомянутых выше программ (некоторые из которых совершенно бесплатны) любой желающий с легкостью может увидеть, какие именно ключи Registry вы пишете или читаете и к каким файлам обращаетесь. Далее, найти соответствующие вызовы в самой программе - дело техники, на то отладчики/дизассемблеры и существуют. Все известные мне shareware-программы с защитой этого класса (например, Bounds Checker Professional) уже давно вскрыты…

Даже при использовании аппаратных ключей успех не гарантирован. Идея сама по себе неплохая, но все проверки происходят все-таки в самой программе (или в библиотеках, поставляемых с этими ключами), а значит, от неприятностей вы не застрахованы - вышеупомянутые способы взлома могут быть с успехом применены и здесь.

"Джентльменский набор" хакера

На первом месте стоит, естественно, дизассемблер. Он значительно проще в обращении, чем отладчик, и часто его бывает более чем достаточно, чтобы "расколоть" программу среднего уровня защиты.

Из всех известных мне дизассемблеров самым мощным является IDA (Interactive DisAssembler), см. ссылка скрыта; он далеко не бесплатный (149 долларов), но, поверьте, вложенные в него деньги окупятся с лихвой. Кстати, эта программа написана нашими соотечественниками. Одной из ее отличительных черт является "многоплатформность" - он "понимает" множество форматов файлов, включая DOS COM/EXE, NE (New Executable), LE (Linear Executable, PE (Portable Executable), COFF (Common Object File Format), NLM (NetWare Loadable Modules), LIB, AR и даже Java-классы. Спектр поддерживаемых процессоров тоже весьма широк: Intel (от 8080 - помните такой? - до Pentium Pro и Pentium MMX, и даже i860), а также Motorola 68xxx, ARM, TMS и многие другие. Причем пользователи могут расширять этот список, добавляя поддержку других процессоров самостоятельно.

Есть у IDA и много других замечательных возможностей, часть из которых действительно уникальны. Например, FLIRT (Fast Library Identification and Recognition Technology); с помощью этой технологии дизассемблер способен распознавать вызовы библиотечных функций (например, для языка C - printf, strcmp и т. д.), включая те, которые вы написали сами. Мало того, IDA еще и умеет идентифицировать обращения к массивам и структурам, делая ассемблерный текст значительно более читаемым. Не могу не упомянуть и об "autocommenting" - результирующий текст получается хорошо закомментированным! И последняя маленькая, но важная деталь: в IDA вы можете "подправить" текст программы (заменяя исходные инструкции ассемблера на свои собственные) и сохранить результирующий EXE-файл, так что даже patch делать не придется.

Если все же IDA вас чем-нибудь не устраивает, сходите по адресу ссылка скрыта, - там собрана целая коллекция ссылок на различные дизассемблеры. Рекомендую также посетить ссылка скрыта, где помимо дизассемблеров есть еще и ссылки на утилиты для редактирования бинарных файлов - тоже пригодятся.

Далее - хороший отладчик. Забудьте о Borland Turbo Debugger и Microsoft WinDbg! Эти программы хороши только для "ловли блох", то есть ошибок. Лучший выбор - SoftICE от NuMega (ссылка скрыта). С его помощью вы можете делать буквально все! Собственно, главное его предназначение - это все-таки поиск ошибок, но и как хакерский инструмент он просто незаменим.

Не обойтись и без уже упомянутых утилит FileMon, RegMon и (возможно) VxDMon, написанных Марком Руссиновичем, известным экспертом в области низкоуровневого программирования для Windows (именно он рассказал всему миру о том, что разница между Windows NT Workstation и Windows NT Server - это всего лишь несколько дополнительных программ и значение одного ключа в Registry). FileMon показывает детальную информацию обо всех обращениях к файловой системе; имеется возможность устанавливать различные фильтры и даже отслеживать работу со swap-файлом.

RegMon (как вы уже, наверное, догадались) делает примерно то же самое, но не с файловой системой, а с Registry.

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

FileMon и RegMon существуют в версиях для Windows 95 и Windows NT (в том числе и для процессора Alpha); VxDMon, естественно, работает только под Windows 95. Все три утилиты можно загрузить с узла "NT Internals" (ссылка скрыта), причем вместе с исходными текстами на C.

Если вам вдруг понадобится что-то еще или просто станет интересно, какими другими инструментами пользуются хакеры, заходите на ссылка скрыта - там собрана большая коллекция ссылок на всяческие полезные (не только для вскрытия) программы.

Как не надо делать

Одна из самых примитивных и ненадежных защит - привязка к компьютеру. Любой программист знает, как получить некие уникальные для данного компьютера характеристики - например, серийный номер винчестера, и (казалось бы) - вот оно! Даже если зарегистрировавшийся пользователь передаст свой ключ кому-то другому, работать программа не будет. Если вы когда-нибудь устанавливали "Лексикон", то знаете, о чем идет речь…

Схема, например, может быть следующей: программа вычисляет упомянутые уникальные данные и показывает их пользователю; он посылает их автору, который (при подтверждении оплаты) вычисляет на их основе соответствующий пароль и посылает его обратно. В программе "прошит" тот же самый алгоритм, и делается сверка ключей - введенного с правильным.

Рекомендую отказаться от этой идеи. Ничего, кроме неудобств для легальных пользователей, она вам не принесет. Что, если пользователь поменяет компьютер? Или хотя бы жесткий диск? В наше время повальной модернизации такое случается сплошь и рядом. Сломать-то такую защиту - как два байта переслать, а вот у вас головной боли будет на порядок больше.

Если вы используете статические ключи, то хотя бы постарайтесь, чтобы их не было видно "невооруженным" взглядом при просмотре EXE-файла. Не надо делать таких "подарков"… Даже если вы будете хранить коды "задом наперед" и/или "зашифруете" их "мощной" функцией XOR (особенно на C или Паскале), то это не поможет. Ассемблер - лучший язык! Как говорится, "заграница нам поможет" - читайте документацию по процессорам Intel (причем не только на сервере Intel - ссылка скрыта; не поленитесь зайти также на сайт "Intel Secrets": ссылка скрыта). Один из законов Мерфи гласит: "Если ничего не получается - прочтите, наконец, инструкцию"… Алгоритмов шифрования в природе много, и вы даже можете придумать свой собственный (естественно, вряд ли вы скажете новое слово в математике, но такая цель и не ставится).

Если же вас привлек кодогенератор, то сделать его надо как можно сложнее, чтобы любителям "халявы" жизнь медом не казалась. Большинство виденных мною защит, построенных на подобном принципе, "колются" в два счета - можно просто "вырезать" часть кода из защищенной программы (сам алгоритм генерации ключей) и сделать программку, которая будет работать по тому же принципу, но уже как отдельное приложение, давая таким образом не очень честным пользователям возможность сгенерировать правильный код совершенно бесплатно.

Кстати, если/когда вы (в программе) определили, что она работает из-под отладчика или что кто-то уже натравил на нее patch (так, что файл изменился, - подробнее об этом см. ниже), то не стоит кричать об этом на всю Ивановскую: поймал, поймал! Это самое глупое, что вы можете сделать, - данная проверка тут же будет локализована и уничтожена.

А как надо?

Конечная цель - сделать абсолютно "непробиваемую" защиту - увы, недостижима, но вы должны к этому стремиться. Программа-минимум - это обеспечить невозможность подбора пароля (регистрационного ключа). Если у хакеров не будет другого выхода, кроме как написать crack (patch), то это уже весьма неплохо: с выпуском очередной версии им снова придется напрягаться. Скажем, к почтовой программе The Bat! (ссылка скрыта) crack имеется, а вот кодогенератор сделать не удалось.

Повторюсь еще раз: изучите, наконец, ассемблер. Все эти новомодные RAD-средства хороши только для рисования окошек, кнопочек и прочих "фенечек", но никак не для мощной защиты. Поверьте, знание ассемблера не мешало еще никому.

Хорошая идея - использование сильных средств шифрования с открытым ключом. Алгоритмов можно найти множество, и даже свободно распространяемые исходные тексты в сети имеются. Не поленитесь, проведите денек в Интернете и изучите литературу по этой тематике, - даже если не пригодится для защиты, то уж, в любом случае, кругозор расширите.

Кстати, рекомендую вам попробовать сжать свою программу каким-нибудь упаковщиком. Помните старый добрый PkLite? Так вот, подобных программ для Win32 уже довольно много. Почти для всех из них существуют "распаковщики", но тем не менее применение этого способа несколько затруднит взлом.

Появились и "интеллектуальные" упаковщики, которые серьезно могут помочь вам защитить вашу программу. Например, Shrinker (ссылка скрыта) - для него (пока) распаковщика не существует, и я не уверен, что таковой может быть написан вообще (упакованный эти пакетом EXE-файл распаковывается динамически небольшими блоками, причем используемый алгоритм достаточно сложен; кроме того, используются и некоторые методы защиты от прохождения кода отладчиком).

Не лишним будет и код, распознающий активность отладчика, причем делать это надо на "ранней" стадии, а не непосредственно перед проверкой введенного пароля. Пустите вашу программу по "ложному пути", совершая действия, отличные от тех, которые выполняются при нормальной работе. Или установите какой-нибудь флажок, который может быть использован позднее (конечно, используя hardware breakpoints, его рано или поздно отловят, но это в любом случае еще одно очко в вашу пользу).

Если у вас есть опыт программирования драйверов, то можно "зашить" защиту и в виртуальный драйвер. Копаться в драйвере намного сложнее, чем в обычном исполняемом файле, и далеко не каждый хакер на это способен. Отлаживать драйвер под Windows NT - вообще сущая морока (для этого нужен второй компьютер с debug-версией NT, или хотя бы второй монитор, или навороченный отладчик типа SoftICE, не говоря уж о высокой квалификации).

Впрочем, все это ерунда. Главное - подходите к делу творчески! Включите свою фантазию, бейте хакеров их же оружием! В конце концов, если вы целый год писали программу и относитесь к ней как к своему ребенку - не поленитесь потратить пару недель на изучение всевозможных систем защиты и, главное, методов их взлома.

"Вредные советы", или Как испортить жизнь хакеру

Итак, почему ваша защита настолько примитивна и может быть легко вскрыта? Обычно по двум простым причинам: во-первых, вы не знаете, как защиты "ломаются" (после прочтения этого материала, надеюсь, знаете). И во-вторых: вы не умеете программировать на ассемблере; практически все защиты, написанные на языках высокого уровня, можно обойти в два счета. Чаще всего достаточно бывает поменять всего пару байт…

Вот несколько советов, которые, надеюсь, позволят вам хоть немного обезопасить свою программу от взлома (по меньшей мере, начинающими и/или не слишком квалифицированными хакерами).
  1. Пишите защиту на ассемблере.
  2. Никогда не давайте осмысленные имена важным функциям, типа IsValidSerialNum.
  3. Не предупреждайте (сразу) пользователя о том, что защита нарушена. Лучше сделайте это через два-три дня - хакеры это ненавидят… Пустячок, а приятно.
  4. Используйте "перекрестные" проверки CRC-кодов ваших EXE- и DLL-файлов.
  5. Делайте паузу (одной-двух секунд будет вполне достаточно) после ввода пароля (серийного номере) перед возвратом результата. При этом подобрать правильный пароль путем прямого перебора (с помощью специально написанной программы) будет совершенно невозможно.
  6. Сохраняйте пароли в каком-нибудь "необычном" месте, например, в свойствах поля базы данных.
  7. Не привязывайтесь к системной дате. Вычисляйте текущую дату из времени создания каких-нибудь системных файлов, например SYSTEM.DAT или USER.DAT (Windows Registry).
  8. Сохраняйте пароль в нескольких местах одновременно.
  9. Не используйте "статические" (то есть жестко прошитые в вашу программу) строчки текста для уведомления пользователя о том, что пароль правильный (или неправильный). Это первое, на что смотрит хакер. Генерируйте эти строчки динамически, или используйте шифрование, хотя бы самое простенькое.
  10. Используйте "мелкие хитрости" для защиты от дизассемблирования и отладки.
  11. Наконец, никому никогда не рассказывайте о том, как построена ваша защита :)

Все эти рекомендации взяты с Web-сайта "Fravia's Page of Reverse Engineering" (ссылка скрыта). Очень рекомендую, обязательно зайдите: здесь есть чему поучиться. Помимо описания стратегий взлома различных защит, вы найдете немало советов для shareware-программистов, которые помогут вам написать действительно хорошую защиту. И еще: посмотрите, кому и за что там присудили "Most Stupid Protection Award" - получите массу удовольствия. Я надеюсь, что сами в этом списке вы никогда не окажетесь… Кстати, сайт довольно хорошо оформлен и легок в навигации; само по себе это не заслуживало бы внимания, но обратите внимание на логотип "Created with MS-DOS EDIT.COM" (вот тебе, бабушка, и Юрьев день - читай: FrontPage).

Некоторые пункты, возможно, требуют пояснения… Более детальные рекомендации вы сможете найти все на том же сайте, но от вас опять-таки потребуется хорошее знание ассемблера. Остановлюсь лишь на пункте 4. Что такое CRC, я думаю, вы знаете, не правда ли? Сразу предупреждаю, при вычислении CRC-кода исполняемого файла вы столкнетесь с некоторыми трудностями: если "правильный" CRC хранится в самом файле (а именно так и стоит делать - если он лежит во внешнем файле или в Registry, то его обнаружат в момент), то его придется каким-то образом учитывать при вычислениях. Выход следующий: просто исключите сам CRC-код из вычислений. Как это сделать, подробно описано в книге Лу Гринзоу "Философия программирования для Windows 95/NT" (издательство "Символ", 1997 год). Кстати, там же вы найдете и множество других полезных советов, так что рекомендую…

Что касается защиты от дизассемблеров и отладчиков, то это, честно говоря, помогает не сильно, - квалифицированный хакер все равно вас перехитрит. Как бы ни был высок ваш профессиональный уровень, все равно найдется кто-нибудь сильнее вас. Тем не менее, чем больше подобных "примочек" вы используете, тем меньше будет круг хакеров, способных взломать защиту. На самом деле, специалистов "высшего пилотажа" в области взлома не так уж и много - во всяком случае, меньше, чем вы предполагаете (большинство считающих себя таковыми на самом деле ими не являются, как бы им этого ни хотелось). Когда человек начинает разбираться в ассемблере как Бог, ему становится не до таких глупостей, как взлом чужих программ, - за это, в конце концов, денег не платят. Ломать shareware-программы - занятие неблагодарное, и специалист высокого класса без проблем найдет себе высокооплачиваемую и интересную работу по душе.


Лекция 7. Тема: Обеспечение безопасности при работе в среде Windows XP

Операционная система Microsoft Windows XP вышла на рынок 25-го ноября 2001-го года. Сотрудники компании возлагали на неё большие надежды и, как оказалось, не прогадали. По заявлению самих разработчиков, новоиспеченная на тот момент XP включала в себе опыт, накопленный за многие годы построения операционных систем.

Как и ожидалось, перед выходом, пользователям было дано множество обещаний (к примеру, непробиваемую защиту от несанкционированного доступа, невиданную ранее стабильность и "багоустойчивость"), но не все оказалось настолько уж гладко.

Но довольно лирических отступлений, сегодня на повестке дня - повышение безопасности операционной системы. Пошаговый формат выбран не с проста - так наиболее просто выполнять инструкции, описанные в статье.