![](https://habrastorage.org/getpro/habr/post_images/d18/3e7/72d/d183e772dc6b784cbb19fa9f3fc6c7ca.png)
![](https://habrastorage.org/getpro/habr/post_images/1af/803/e89/1af803e89617eb5d248a4ca85198385c.png)
В статье читайте:
- Про «лицензию», «активацию», «хэш-функции», «цифровую подпись», «асимметричную криптографию» и (вкратце) про RSA и DSA, без формул и математики.
- Чем механизм подписки (subscription) отличается от традиционного лицензирования.
- Применение описанных принципов на примере EXE-протектора VMProtect.
Итак, приступим.
Как подписочная программа работает с сервером лицензий
Т.к. мы продвигаем идею ежемесячных микросписаний за использование коммерческого ПО (вместо традиционной продажи дорогих «разовых» ключей), для нас представляет интерес то, как программа должна взаимодействовать с сервером лицензий на периодической основе, чтобы ее нельзя было «обмануть».
Подписка — это возможность работы программы за ежемесячную абонентскую плату. Когда оплата не поступает, программа блокируется — и наоборот, если деньги пришли, она продолжает работать.Естественно, продукт должен как-то определять, может ли он запускаться в каждый конкретный момент времени или нет (заблокировалась ли подписка из-за недостатка средств на счете). Для этого он использует доступ в интернет и регулярные (например, раз в 5 дней) обращения к специальному серверу лицензий.
![](https://habrastorage.org/getpro/habr/post_images/107/93d/cd4/10793dcd483ef4a2d9907234d81d09c6.jpg)
![](https://habrastorage.org/getpro/habr/post_images/1af/803/e89/1af803e89617eb5d248a4ca85198385c.png)
Но чтобы понять всю схему, проведем небольшой экскурс в традиционные способы работы с «бессрочными» ключами и механизмы асимметричной криптографии.
Что такое активация ключа?
Традиционно при электронной покупке той или иной программы пользователю высылают сгенерированный специально для него ключ (или лицензию, или серийный номер — кто как называет). Пользователь затем вводит этот ключ в запущенный продукт и, в конечном итоге, активирует его (заставляет работать).
Как программа, приняв ключ, определяет, что он достоверен? Для этого существует два основных способа:
- Можно проверить, что ключ был сгенерирован по специальному алгоритму, известному программе, и, если это не так, блокировать работу. Так поступали в старину, когда еще не было всеобщей интернетизации. Естественно, в данном случае ключ может быть украден и в дальнейшем использован на другом компьютере, так что данный способ ненадежен.
- Программа может попросить для активации «обратной связи» у своего разработчика: пользователь сообщит разработчику ключ и какую-то дополнительную информацию о себе, а разработчик на основе этих сведений поймет, разрешить ли программе работать (активировать ее или нет).
![](https://habrastorage.org/getpro/habr/post_images/d2a/803/87c/d2a80387cc061dc961e37ae672698d6e.jpg)
Обратите внимание, что в данном примере в качестве «дополнительной информации о себе» использовался идентификатор оборудования — хэш-код, более-менее уникально идентифицирующий машину пользователя. У того, кто ключ украдет, этот хэш-код будет уже другим, так что, позвонив в службу поддержки, он ничего не добьется — там поймут, что производится попытка повторной активации.
Активация через интернет
С приходом интернета в каждый дом необходимость в телефонных звонках отпала: теперь программа сама «звонит» на так называемый сервер лицензий разработчика, «диктует» ему ключ и код оборудования, а взамен ей «сообщают» код активации, которым сама себя и активирует. По этой схеме сейчас работает подавляющее большинство программ, и она довольно надежна.
В общем, у нас образовались следующие сущности:
- Ключ: то, что выдается пользователю при покупке.
- Идентификатор оборудования: некоторое число, с той или иной степенью уникальности характеризующая компьютер пользователя (на разных компьютерах оно будет разным).
- Код активации: закодированное «разрешение» программе запуститься, если пользователь имеет «на руках» определенный ключ и определенный идентификатор оборудования.
- Сервер лицензий: некоторый сервер в интернете, подконтрольный разработчику и умеющий по паре «ключ» + «идентификатор оборудования» возвращать пользователю код активации.
Открытый и закрытый ключ: асимметричная цифровая подпись
Казалось бы, можно вычислять значение
activationCode = md5(key + hardwareID)
: в этом случае и сервер лицензии сможет его сгенерировать, и программа у клиента — проверить правильность.Однако здесь кроется серьезная опасность: раз сервер лицензий может вычислить это значение, то и злоумышленник — тоже. А значит, злоумышленник может сделать свой собственный сервер лицензий, «подставить» его вместо исходного и… получить неограниченный контроль над программой. Что же делать?
Говорят, что у каждой сложной задачи есть одно простое, логичное, легкое для понимания… неправильное решение. В данном случае таким неправильным решением была бы формула
activationCode = md5(key + hardwareID + salt)
где
salt
— некоторая «секретная» строка, известная только серверу лицензий разработчика. К сожалению, такой трюк с «солью» не пройдет, потому что программа у клиента тоже должна иметь возможность вычислить значениеВообще, значение
S = md5(X + salt)
называют «цифровой подписью данныхX
с сольюsalt
». Проверить цифровую подписьS
означает снова вычислитьmd5(X + salt)
, уже на другой стороне, и сравнить результат сS
: если совпало, то подпись верна, если нет — то имеет место подделка.
md5(key + hardwareID + salt)
, а значит, salt
должен быть «вшит» в нее изначально. Конечно же, злоумышленник сможет дизассемблировать продукт и найти в нем salt
, после чего организовать поддельный сервер лицензий. Мы вернулись к тому же, с чего начинали.Но решение есть, и называется оно DSA. Оказывается, существует такой алгоритм, который, грубо говоря, позволяет получать хэш-код
activationCode
при помощи одного значения salt0
, а проверять «правильность» этого хэш-кода — уже с совершенно другим значением salt1
. Значение salt0
нужно держать в секрете — оно хранится только на сервере лицензий, в то время как salt1
никакой ценности для злоумышленника не представляет — зная его, он все равно не сможет получить salt0
и вычислить правильные коды активации.Таким образом, сервер лицензий вычисляет цифровую подпись
activationCode = DSA(X, salt0)
и передает значение программе клиента, а программа — проверяет ее правильность при помощи алгоритма DSA_check(activationCode, X, salt1)
. В этом случае salt0
называют «закрытым ключом» (private key), а salt1
— «публичным ключом» (public key). «Публичным» ключ называется потому, что его можно хоть в газете напечатать — это не нанесет вред безопасности.Подробности про алгоритм цифровой подписи DSA и основанный на том же принципе алгоритм шифрования данных RSA можно почитать в Википедии на русском языке. Вкратце — принцип работы RSA основан на так называемой «проблеме факторизации» — сложности разложения больших чисел на множители. Действительно, имея два каких-нибудь 2000-значных простых числаX
иY
, можно за микросекунду вычислить их 4000-значное произведениеS = X * Y
. Однако, имея это произведениеS
и не знаяX
илиY
изначально, за время существования Вселенной невозможно восстановить исходныеX
иY
, из которых оно составлено. На качественном уровне можно считать, что для составления цифровой подписи DSA используются числаX
иY
(закрытый ключ), а для проверки — общеизвестныйS
.
Вернемся снова к подписке
В самом начале мы говорили, что подписка — это просто более частое обращение к серверу лицензий, который возвращает все новые и новые коды активации, в то время как старые коды активации — устаревают. Для такого устаревания алгоритм создания кода активации должен быть более сложным: в коде как минимум «зашивают» даты начала и окончания срока его действия (начала — чтобы пользователь не переводил часы слишком уж назад).
![](https://habrastorage.org/getpro/habr/post_images/2df/465/d77/2df465d77dc9f9c770dd751ea5c8bd1a.gif)
- Регулярно и в фоновом режиме программа делает попытку обращения к серверу лицензий, чтобы получить от него свежий код активации. На сервер передается ключ и идентификатор оборудования, упрощенно —
GET /license_server?key=abcdef&hwid=1234
- Если попытка была неудачной, то ничего не происходит — никаких сообщений не выдается.
- В случае же удачи свежий код активации, выданный сервером, записывается в какое-нибудь постоянное хранилище (например, в Реестр) — все равно он не представляет интереса для злоумышленника, т.к. он не сможет его использовать у себя (код активации зависит от идентификатора оборудования, который будет у злоумышленника другим).
- Независимо от этого программа берет текущий код активации из постоянного хранилища и проверяет его цифровую подпись, используя ключ, идентификатор оборудования и открытый параметр salt1. Если код активации верен, то программа продолжает работать (возможно, попутно извлекая из кода какие-то необходимые данные — например, параметры шифрования кода виртуальной машины, как это делается в VMProtect).
Т.е. при работе по подписке код активации запрашивается регулярно, а в случае работы «традиционной» схемы с активацией ключа — единоразово. В этом заключается техническое различие. Конечно, сервер лицензий должен работать надежно и выдерживать высокие нагрузки, поэтому у нас их две штуки в балансировке, написаны они на Java Netty — фреймворке для создания асинхронных веб-серверов, том самом, на который недавно перевел свой поиск Twitter. Но это уже тема для отдельной статьи.
Пример создания подписочной версии вашей программы
Выше была теория о том, как может работать сервер лицензий, обслуживающий запросы на проверку статуса подписок. Теперь немного коснемся практики и посмотрим, как разработчики VMProtect Software реализовали эту теорию при создании подписочной версии протектора VMProtect для нашей платформы RentSoft.
Создание приложения HelloWorld и его MAP-файла
Для начала создадим программу типа «Hello, world!», которую и будем защищать VMProtect-ом. Будем использовать MS Visual Studio 2010: создадим в ней новый проект типа «Win32 Application» и назовем его HelloWorld. Главный файл будет выглядеть примерно вот так:
#include "stdafx.h"Сразу переключим режим построения проекта на Release в Диспетчере конфигураций. После этого включим генерацию MAP-файла: он будет содержать адреса всех функций внутри EXE-файла, чтобы их смог потом найти VMProtect. Это делается в свойствах проекта, в русской версии путь такой: кликнуть правой кнопкой по имени проекта в Обозревателе решений, дальше выбрать Свойства конфигурации — Компоновщик — Отладка — Создавать файл сопоставления.
…
ATOM MyRegisterClass(HINSTANCE hInstance)
{ ... }
…
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{ ... }
...
Теперь нажмем F5 и убедимся, что проект откомпилировался и запустился. Мы получили в директории Release 2 файла:
HelloWorld.exe
и HelloWorld.map
, с которыми и будем работать.![](https://habrastorage.org/getpro/habr/post_images/dd6/c0b/406/dd6c0b406e02f5f9a0fad12089a7e49a.png)
Мастер регистрации продукта на сервере лицензий RentSoft
Подписочная версия программы работает в тесной связи с сервером лицензий, который, собственно, и занимается проверкой статуса ключа и определением, может программа работать или нет. Сервер лицензий должен иметь информацию о продукте: например, закрытый ключ RSA-шифрования и другие параметры лицензирования, так что продукт нужно на нем зарегистрировать.
Это довольно просто: по адресу http://rentsoft.ru/soft/add/ выбираем вариант «VMProtect RentSoft Edition (бесплатно для клиентов RentSoft)», вводим свой e-mail (подтверждать его, кстати, не потребуется) и попадаем в Мастер регистрации продукта. В нем мы вводим следующие данные:
- Название продукта, краткое и подробное описание (можно использовать HTML).
- Изображение коробки с продуктом (или его логотип).
- Выбираем желаемую стоимость подписки в месяц — например, 79 рублей.
![](https://habrastorage.org/getpro/habr/post_images/660/c7f/c1c/660c7fc1cbb683d0f02b6e7b78656ee5.png)
Файл лицензии необходим для привязки защищаемой программы к продукту, который мы только что зарегистрировали на сервере лицензий. Сохраните его в директорию с исходным кодом проекта — в нашем случае рядом с
HelloWorld.cpp
.Запуск VMProtect для создания подписочной версии
Далее запустите VMProtect RentSoft Edition (ссылка на его скачивание его инсталлятора приведена на следующем шаге мастера). Это протектор EXE-файлов, созданный нашими партнерами — компанией VMProtect Software. Откройте через Файл — Открыть EXE-файл проекта
Release/HelloWorld.exe
и установите параметры, как на скриншоте (главное — укажите путь к файлу лицензии проекта):![](https://habrastorage.org/getpro/habr/post_images/14d/a1f/1bf/14da1f1bf2419772b57f924e4fef91a1.png)
Теперь перейдите на вкладку Процедуры для защиты и выберите на ней те процедуры и функции, которые хотите защитить VMProtect-ом (код этих процедур будет переведен в код виртуальной машины VMProtect и привязан к продукту, зарегистрированному ранее на сервере лицензий).
![](https://habrastorage.org/getpro/habr/post_images/aee/088/5c7/aee0885c7a20698113fd10a055429078.png)
В нашем случае мы указали 2 функции:
MyRegisterClass
и WndProc
— именно их теперь хакер не сможет «взломать». Обратите внимание: нужно выбрать Тип компиляции «Ультра» (самый надежный), а также поставить флажок «Привязать к серийному номеру» в «Да». Старайтесь защищать те функции программы, которые некритичны к производительности, потому что виртуальная машина работает, естественно, медленнее, чем «родной» процессор. (Не забудьте после всех манипуляций сохранить файл проекта VMProtect: в нем содержатся все опции, которые вы выбрали, чтобы при следующей защите не нужно было их выбирать заново: Файл — Сохранить проект как...)Что будет, если злоумышленник все же сможет расшифровать код виртуальной машины VMProtect для какой-то защищенной программы (что крайне сложно само по себе — вспомните, сколько попыток было расшифровать, например, Skype, который тоже использует технологию виртуализации кода)? Это не даст ему доступа к другим программам: ведь для работы виртуальной машины требуется информация, содержащаяся в коде активации, а она для каждой программы — разная. Так что, не имея кода активации, выданного сервером лицензий, заставить программу работать физически невозможно. Подделать сервер лицензий тоже не получится — помните про технологию открытых/закрытых ключей?Наконец, выберем Проект — Компиляция и подождем несколько секунд. В результате рядом с
HelloWorld.exe
появится файл HelloWorld.vmp.exe
— его защищенная версия. Именно этот файл и является «подписочной» версией вашего продукта.Проверяем, что получилось
Если теперь запустить
HelloWorld.vmp.exe
, мы увидим вот что:![](https://habrastorage.org/getpro/habr/post_images/eff/e3d/d67/effe3dd67c76bf080c6a29ef5419f1ae.png)
Т.е. программа при первом запуске просит пользователя ввести «код подписки», который он получил на одной из витрин RentSoft, когда подключил себе ваш продукт. Естественно, сервер лицензий RentSoft в курсе всех активных кодов подписки, что позволяет ему обрабатывать запросы от программы и проверять код, введенный пользователем.
Теперь нужно ввести код подписки. Где его взять для проверки? Мы могли бы здесь отправить читателя на витрину продукта и сказать «подпишитесь на продукт — получите код подписки», но можно поступить проще. Мастер регистрации продукта RentSoft, в котором мы только что находились, позволяет создавать тестовые подписки на сервере лицензий. Т.е. все, что вам требуется, — это нажать кнопку Создать в форме:
![](https://habrastorage.org/getpro/habr/post_images/8e3/eae/c5f/8e3eaec5f9fe5ffb430dd47e062f1417.png)
В итоге вы получите тестовый код подписки, который останется ввести в окно активации программы:
![](https://habrastorage.org/getpro/habr/post_images/f5a/8b3/15c/f5a8b315c1a011c1318f62ca76eb7fbd.png)
После этого программа запустится и больше не будет ничего спрашивать у пользователя до тех пор, пока на его счете имеются деньги (т.е. пока подписка активна).
Предположим, денег на счете для продления нет...
Что произойдет, когда у пользователя кончатся деньги и подписка заблокируется? Не обязательно ждать месяц, чтобы это увидеть: можно воспользоваться все той же формой работы с тестовыми подписками, которая теперь примет вот такой вид:
![](https://habrastorage.org/getpro/habr/post_images/7c5/c83/252/7c5c83252540f79d313a2b2a58e64011.png)
Заблокируйте тестовую подписку, после чего перезапустите программу дважды: во второй раз она заблокируется с выводом сообщения о недостатке средств на счете. (Почему дважды? Считайте, вам дается последний шанс воспользоваться продуктом перед тем, как он заблокируется.)
Возможно, вы спросите, что будет, если подписку заблокировать, а интернет — отключить, и уже после этого запустить программу. Тогда программа, естественно, не узнает, что она не может функционировать, и будет работать… но только следующие 5 дней. Через 5 дней программа потребует обязательный доступ в интернет и откажется запускаться, если связи не будет: истечет так называемый «период толерантности». Так что пользователь все равно должен будет пополнить свой счет, рано или поздно.
Что касается автоматической разблокировки при поступлении средств на счет, то вы можете проверить, как это работает, нажав кнопку «Включить» и перезапустив программу. Если связь с интернетом имеется, программа немедленно продолжит работу.
В заключение — про наши каналы продаж
![](https://habrastorage.org/getpro/habr/post_images/e31/9ef/02f/e319ef02fcdd4940d865e0a0d09a7a49.png)
Главное преимущество продажи по схеме ежемесячной подписки через интернет-провайдеров в том, что абоненты и так уже ежемесячно приносят провайдеру 400-500 рублей оплаты за интернет. Мы умеем списывать оплату за ПО (которое в этом случае выглядит, как дополнительная услуга провайдера) прямо со счета абонента. Поэтому, когда пользователь подключает вашу программу на сайте провайдера или в его личном кабинете, он оплачивает ее в том же чеке, которым платит за интернет! Одним словом, это очень эффективный канал.
Так что, если вы разрабатываете десктопный софт, но продаете его в основном на Запад, мы бесплатно предоставляем вам инструменты, чтобы попробовать продавать в России по схеме ежемесячной подписки. Мы, как любая платежная система, работаем за комиссию с совершенных пользователями транзакций, но, т.к. вы сами определяете ежемесячную цену на свой продукт, это не должно являться проблемой.
Присоединяйтесь!