Регистрация основанная на серийных ключах

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

Дело в том, что при хорошем знании ассемблера очень просто его обойти: когда пользователь вводит свое имя и регистрационный код, программа генерирует "правильный" код и сравнивает его с тем, который он ввел, поэтому "перехватить" этот код (просто считать его из памяти) не составлет особого труда. В большинстве случаев достаточно просто поставить breakpoint на функцию lstrcmp - и все дела... Упаковка программы, анти-дебаггерные и анти-дизассемблерные "примочки" помогают слабо. Очень рекомендую заглянуть на fravia.org - там много чего по этому поводу написано.

А вот первый метод может быть реализован достаточно неплохо. Хранить "правильные" ключи в программе совсем не обязательно - можно подчинить их некоторым правилам; что-то подобное делает Microsoft со своими CD-keys, но у них все слишком просто. Алгоритм проверки может быть длинным и запутанным, так что его дизассемблирование (и "разборка", что же он делает) причинит немало головной боли. Именно первый метод я и применил для защиты своей программы (Advanced Disk Catalog - старые версии), но и он был "сломан" (хотя, как мне написал ломавший его хакер, подборка всего двух правильных ключей отняла у него много времени). Тогда мне в голову пришла идея: а что, если ключи хранить внутри программы, но зашифрованными? Я "сгенерил" некоторое количество ключей (абсолютно случайным образом), зашифровал их (по отдельности) 128-битным ключом по алгоритму RSA и прошил в программу в виде ресурса. Когда пользователь вводит ключ, он шифруется по тому же алгоритму и сравнивается с правильными. Так как система с открытым ключом не позволяет произвести обратное преобразование, базируясь только на открытом ключе (а закрытого нет даже у меня - расшифровывать-то не надо), то подобрать ключи невозможно даже теоретически.

Есть, впрочем, еще одна проблема: хакер (или "крэкер", если угодно) может заменить 'je' на 'jne' (или что-то в этом роде) там, где происходит последняя проверка, и функция "IsValidKey(...)" будет всегда возвращать TRUE. Останется лишь написать маленький patch... Чтобы защититься и от этого, я вычисляю CRC своего exe-файла и сравниваю его с правильный, прошитым тоже внутри программы (естественно, при вычислении эта часть файла - где лежит правильный CRC - исключается; а "прошивается" он после компиляции). Кстати, это еще и защита от вирусов. Вообще-то, проверку CRC тоже можно локализовать и "запатчить", но это уже немного сложнее, особенно если программа вызывает функции чтения/записи и для других целей. Кроме того, не стоит в случае несовпадения CRC сразу об этом сообщать, иначе можно будет поставить hardware breakpoint и найти место, где он вычисляется. И последнее. Если хочется защитить программы совсем уж "круто", томожно несколько функций в своей программе (те, которые должны вызываться только в зарегистрированной версии), зашифровать по тому же алгоритму с открытым ключом. При этом, естественно, часть серийного номера (отсылаемого зарегистрировавшимся) надо сделать "статическим", т.е. неизменным для всех пользователей. На основе этой части после регистрации генерируется полный закрытый ключ, который далее используется для расшифровки указанных функций. Таким образом, даже если будет написан patch, позволяющий "зарегистрироваться" с любым (произвольным) кодом, расшифровка пройдет неправильно, и вместо нормального кода будет выполняться "мусор".

Этот способ я применил в другой своей программе (Advanced ZIP Password Recovery), и ее пока не вскрыли. Всего наилучшего, Vladimir Katalov

Managing Director Elcom Ltd.


Дополнение по взламыванию программ основанных на регистраторе (Alexey Vasilyev): регистрационные коды обычно вводятся в стандартных компонентах типа TEdit (в Delphi). Содержимое же считывается при помощи 16-ти разрядных функций GetWindowText или GetDlgItemText, или же при помощи 32 разрядных - GetWindowTextA, GetWindowTextW, GetDlgItemTextA, GetDlgItemTextW, где A - озночает, что на каждую букву отводится 1 байт, a W - 2 байта (используется редко). Затем содержимое кода TEdit'a сравнивается с кодом, полученным в результате преобразования регистрационного имени. Чтобы получить правильный регистрационный код, необходимо прерваться на одной из этих функций, а затем уже просмотреть содержимое стека, регистров или памяти для поиска подходящих значений. Подобные операции лучше производить при помощи оладчика SoftICE for Windows фирмы Numega. Подробные инструкции (на русском языке) для взлома Shareware программ Вы можете скачать отсюда.

Страница обновлена 25 Сентября 2002
Сайт управляется системой uCoz