Автор: gackt На тему защиты Shareware-программ написано уже немало, и вряд ли вы найдете что-нибудь новое в этой статье. Это лишь очерк некоторых методов, наиболее эффективных на мой взгляд. Если вы надеетесь найти здесь конкретные примеры или исходники - я вас огорчу, все описания методов защиты приведены в общем виде, статья содержит только теорию.
Некоторые способы защиты придуманы мной лично (хотя наверняка кто-то уже додумался до них раньше меня). Другие были взяты из посторонних источников. Источники я не указываю по одной простой причине - их очень много, как отечественных, так и зарубежных, и каждый из них присваивает авторство себе. Так что определить настоящего автора того или иного способа невозможно. Статья преследует лишь образовательные цели, а реализация методов предполагает знание программирования, математики и наличие творческого мышления. Любая защита требует творческого подхода, и только работая своей головой вы сможете создать что-либо уникальное, надежное и заслуживающее внимания.
Ключи регистрации
Метод: Генерация ключа
Для генерации ключей ни в коем случае нельзя использовать параметры, вводимые пользователем (имя, email и т.п.). Просто генерируйте ключ, который будет соответствовать некоторым правилам. Многие разработчики для проверки ключа используют регистрационные данные (например имя), генерируют ключ в самой программе, и сравнивают значения – это грубейшая ошибка. Достаточно отловить сгенерированное значение и защита сломана. Лучше используйте серийные номера, соответствующие набору правил, и не привязанные явно к чему либо.
Метод: Защита от кейгенов
Используйте асимметричную криптографию, а именно – цифровую подпись (RSA, DSA, ECDSA… и др.). Подробнее об ЭЦП можно найти на том же яндексе или гугле (yandex.ru, google.com).
Естественно, если ваша программа занимает пару сотен килобайт, и стоит полбутылки пива, то встраивать подобную защиту не имеет смысла – получится Неуловимый Джо, хотя возможно это и к лучшему. К тому же время проверки ЭЦП может занимать до нескольких секунд, так что если вы писали не клон Photoshop или Corel, то пользователю это вряд ли понравится.
Если вы далеки от криптографии и не знаете что такое электронная цифровая подпись – рекомендую все же зайти на google.com и поискать (в интернете информации по ЭЦП навалом).
Для тех кто в танке, т.е. прочитал и до сих пор не понял как ЭЦП может помочь – объясняю:
Вы генерируете 2 ключа – секретный (он будет хранится у вас) и открытый (прошиваете его в программу, причем желательно его зашифровать). На секретном ключе будут подписываться все регистрационные ключи, которые вы высылаете пользователям, на открытом же ключе будет производится проверка подлинности ключа – выписан ли ключ вами (регистратором), или нет. Делайте проверку подписи в первую очередь, если подпись не совпадает – сразу же прерывайте процедуру проверки ключа, тем самым вы не дадите взломщику даже узнать правила проверки ключей. Если все же взломщик получил от вас регистрационный код, подписанный на вашем секретном ключе или, покопавшись с отладчиком, обошел проверку подписи и узнал правила проверки регистрационного кода, то для написания кейгена ему понадобится до нескольких миллионов лет (примерно столько времени уйдет на вычисление вашего секретного ключа из открытого, при солидном модуле преобразований в ЭЦП). Если вы сильны в криптографии и математике вообще, то можете разработать свой алгоритм ЭЦП. Это конечно займет уйму времени, но оно того будет стоить, даже если алгоритм далек от совершенства. Дело в том, что взломщик может подменить ваш открытый ключ на свой, если он знает алгоритм используемой ЭЦП, но если вы использовали свой собственный алгоритм и не предали его огласке, то ему придется еще разбирать ваши труды, пошагово, с отладчиком, что также может затянуться на миллионы лет, все зависит лишь от вашей фантазии.
Естественно ничто не мешает предать регистрационный код огласке, подменить открытый ключ, или выпустить патч – но это уже другая история.
Метод: Hash vs RSA
Недавно мне попалась на глаза статься Владимира Каталова, где он описывал, как использовать направленное шифрование для защиты программ. Суть его метода заключалась в следующем - он генерировал несколько серийных номеров случайным образом, шифровал их по алгоритму RSА на открытом ключе 128 бит, и прошивал в программу в виде ресурсов. Для проверки серийников, он шифровал введенные пользователем значения на том же открытом ключе и сравнивал с прошитыми зашифрованными значениями. Автор хвастался, что не нужен даже секретный ключ, т.к. зашифрованные ключи не нужно дешифровать. Мне лично непонятно - а зачем тогда вообще RSA? Проще хешировать эти серийники и прошить в программу, а при вводе хешировать введенный ключ и сравнивать с прошитыми. К сведению - написание собственного хеша займет не больше дня, если имеются соответствующие навыки. Реализация же RSA требует в несколько раз больше времени, а шифрование занимает намного больше ресурсов системы, чем хеширование. Дабы не повторять его ошибок используйте хеш функции, например Haval или SHA.
Также не имеет смысла использовать направленное шифрование для защиты исполняемого кода, как рекомендует Владимир. В частности, он шифровал фрагменты кода (некоторые функции, которые должны работать только в зарегистрированной копии "Advanced ZIP Password Recovery") тем же RSA, а для генерации ключа дешифрования использовал часть кода регистрации, одинаковую для всех пользователей. Не повторяйте и эту ошибку. С тем же успехом можно использовать любой блочный симметричный алгоритм, например Twofish или AES, это намного быстрее и эффективнее.
Если вы думаете, что RSA надежнее - вы глубоко ошибаетесь. Более надежным может оказаться лишь использование эллиптических кривых с модулем более 2^160 (что по стойкости равносильно RSA с модулем 2^1024), но на реализацию уйдет куча времени, а сложность преобразований сильно скажется на быстродействии. Факторизация же ключа RSA в 128 бит занимает около 143 млн. групповых операций, так что на любом домашнем компьютере секретный ключ дешифрования подбирается за несколько минут.
Метод: Привязка к железу
В этом нет ничего сложного. Достаточно использовать для генерации ключа серийный номер винчестера или проца. Но есть одна загвоздка – апгрейд. Пользователь может сменить винт, проц, да все что угодно. К тому же винчестер – это первое что выходит из строя (из личного опыта). Привязываться же к метке тома просто глупо, пользователь переставит систему – и ключ будет недействителен. Хотя если ваш софт периодически работает с сетью (качалка, почтовый клиент и т.п.), и вы можете обеспечить доставку ключа в течение пары часов, то привязаться к железке – идеальный вариант. Вы можете давать пользователю возможность перезапросить ключ регистрации, т.е. он отсылает свои данные, вы выписываете ему новый ключ, а старый помещаете в базу недействительных.
Еще один вариант - использование ключевых железок (дискет, дисков, HASP ключей и т.п.). Это очень неудобно как для пользователей, так и для вас (реализатора или разработчика). Пользователю надоест каждый раз при запуске программы вставлять дискету в дисковод, или проверять, подключен ли HASP ключ. К тому же такая защита требует начальных финансовых затрат со стороны разработчика. Если вы планируете продавать свою программу через Интернет, то высылать каждому пользователю ключ или дискету может оказаться накладно. Как правило, подобная защита используется лишь для узкоспециализированного и дорогого (стоимостью >200$) ПО.
Метод: Код активации
Конечно могут найтись умники, которые будут внаглую требовать новый ключ каждый день, мотивируя это апгрейдом, потерей ключа, переустановкой системы, вашей проги, или еще чем. Могут и просто использовать ключ, выложенный кем-то на обозрение. В таком случае рекомендую следующее: использовать дополнительно код активации. Привязывайте ключ к email адресу юзера, и высылайте код только на него. Лишняя защита не помешает, если вы разрабатываете действительно серьёзный продукт, рассчитывая получить миллионную прибыль. Совсем не обязательно делать онлайновую проверку ключа при каждом запуске программы. Просто используйте дополнительный ключ (код активации). Каждый раз при регистрации программы (вводе ключа), он может отсылаться на сервер, который будет уже автоматом генерить код, соответствующий некоторым правилам, и высылать его на email, соответствующий введенному ключу. Это поможет избежать таких неприятностей, как использование ключей посторонними. При каждом запросе кода активации проверяйте ключ по базе, и если этот ключ уже недействителен или не существует в базе – не высылайте код. Для оффлайновых программ (например файловых менеджеров, графических или текстовых редакторов и т.п.), такая система не подходит по вполне понятной причине – с Сетью они работают мало, или вообще отношения к ней не имеют.
Хранение ключей
Хранить ключи регистрации в каком-нибудь файле или реестре ненадежно, т.к. отследить и скопировать такой ключ не представляет труда. Для хранения лучше использовать некоторый свободный кластер в файловой системе, и запрещать к нему доступ с помощью драйверов ФС, например, пометив его как поврежденный. Это не защитит на 100% от копирования, но немного затруднит процесс. Перед разработчиком возникают и другие трудности, как определение типа ФС и сложность работы с разными драйверами.
Не храните всякие "секретные" значения, которые определяют, зарегистрирована ли программа. Храните все данные регистрации в том виде, в котором пользователь их ввел.
Защита от патчинга
Метод: CRC и прочие хеши
Для проверки целостности файла можно использовать различные хеши и контрольные суммы. Обойти эту проверку достаточно просто, но лишняя предосторожность не помешает. Храните результаты хеширования в разделах ресурсов исполняемых файлов (желательно в зашифрованном виде), а проверке подвергайте либо исполняемый код, либо весь файл, исключая секцию, где записан хеш. Напишите свою собственную функцию хеширования. Немного усложнив жизнь себе вы очень сильно усложните жизнь взломщику. К тому же написав свою функцию хеширования вам возможно удастся найти коллизию, такую, что хеш от всего файла, будет равен прошитому в файл значению.
Вопреки распространенному мнению проверка CRC в большинстве случаев никак не защищает от вирусов. Только если вирус подменил часть кода в программе. В большинстве случаев вирус просто дописывает себя вначале программы, и запустив программу, вы в первую очередь запустите вирус, а уже потом саму программу, которая проверит свою CRC и благополучно загнется.
Метод: Опять ЭЦП
Можно использовать ЭЦП для проверки целостности исполняемого файла. Проверка осуществляется на открытом ключе. К достоинствам этого метода можно отнести то, что для подмены подписи необходимо вычислить секретный ключ, так что сам результат подписи можно хранить в открытом виде в любом файле. Но не забывайте, что асимметричная криптография забирает много ресурсов.
Метод: Учимся на ошибках
Если вдруг в вашей программе обнаружилась мааааленькая ошибочка, например, выскакивает access violation при сохранении файла, но при этом она никак не влияет на работоспособность программы, а лишь надоедает пользователю – то оставьте её в покое до поры до времени. Начинайте отлавливать такие ошибки только после выхода основного релиза.
Казалось бы, как это может защитить от взлома? Дело в том, что взломщик вряд ли будет отлавливать такую незначительную ошибку в вашей программе, удалять или изменять коды процедур и т.п., это для него лишнее. Его основная цель – снять защиту (слепить кейген или патч к программе). Для пользователя же основная цель – получить работоспособный продукт, и рано или поздно ему надоест видеть десяток окошек с кодами ошибок при каждом сохранении файла. Вот на этом мы и сыграем. Начинайте действовать, когда на ваш почтовый ящик начнут приходить письма с жалобами. Отловив и исправив ошибку не спешите обновлять релиз, а просто выпустите патч. Для применения патча можно проверять сразу кучу параметров, как размер, дата файла, CRC, и т.п. Тут есть 2 пути:
вы можете исправлять ошибку только в оригинальном файле, сгенерив патч как разницу между файлом релиза с ошибкой и файлом исправленного релиза,
снегерить патч как разницу между взломанным исполняемым файлом и оригинальным с исправленной ошибкой, т.е. такой, который приведет программу обратно к не зарегистрированному виду.