Домашняя лаборатория мудрого KAA

Верхом на VMProtect, или как я свою софтинку защищал

Просмотров: 3560Комментарии: 0
Программирование (Programming)Сделал сам (DIY)Новости (news)Delphi
Верхом на VMProtect, или как я свою софтинку защищал

О версиях

  • VMProtect: 309 build 695;
  • WebLN: 2.4.2.21 (см. include\version.inc.php);
  • Delphi 10.1 Berlin;

А почему-зачем?

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

Вообще говоря, я родом из СССР и продавать ничего не люблю, с удовольствием бы раздал, но уж очень хочется съездить с друзьями на Ибицу, да и вообще за границу. Отдохнуть цивилизованно, хоть раз в жизни, мир посмотреть, жену показать ;). Короче, денег хочется, чтобы их в дело произвести (как говаривал Петр I).

А как защищать-то?

Вопрос хороший и, главное, своевременный. Важно, чтобы взлом программы был трудоемкий, а значит дорогой. Чтобы был свой сайт активации. Чтобы пользователь после приобретения софтинки получал короткий код и активировал ее (автоматически или вручную) через мой сайт - менеджер лицензий. В ответ на успешную активацию пользователь должен получать серийный номер. Хочется, чтобы коды активации выдавались автоматически, по запросу агентов электронной коммерции (см. PayPro/Plimus/Avangate/MyCommerce). Ну, и много чего еще хочется.

Может, PhpMyLicense?

Начал искать менеджеры лицензий на PHP. Сначала мой выбор пал на PhpMyLicense. Продукт платный, пробной версии не нашел, поэтому скачал зануленный, чтобы посмотреть, что это за зверь. По большому счету меня интересовал API. В принципе, там он реализован, но программа заточена на лицензирование PHP-скриптов, а не классических Windows-программ. Короче, решил, что можно взять его за основу и немного допились самому. Кстати, видно, что код написан местами непрофессионально, т.к. вероломно не соблюдается концепция DRY. Ну, думаю, вроде с менеджером лицензий разобрался. А код-то защищать чем? Почитал про методы защиты. Понял, что нужно использовать коммерческое решение. Чаще других в сети упоминался ASProtect, видимо, из-за его гуманной цены. Начал разбираться, как его подружить с внешним менеджером лицензий. Оказалось - никак. Мдя. Тоска-печаль, ну будем искать.

A может, Web License Manager?

Вторым продуктом в моем списке был WMProtect. На нескольких форумах есть упоминания о нем как о хорошем средстве защиты благодаря виртуализации кода. Затягивать не стал, зашел на сайт разработчика, и оказалось, что в WMProtect реализованы все мои хотелки и даже больше, включая менеджер лицензий, который у них называется Web License Manager (далее по тексту WLM).

Надо отметить, что WLM стоит 200 баксоидов, что соизмеримо с ASProtect, который сейчас стоит 173 евроида.Но это только менеджер лицензий! WMProtect Ultimate стоит еще 400 баксоидов. Четыреста баксов, Карл! И это персональная лицензия.

Короче, если вы честный гражданин, то вам это удовольствие обойдется в 600 Вашингтонов. Обзор функциональности разных типов лицензий WMProtect можно посмотреть по адресу: http://vmpsoft.com/products/matrix

VMProtect Lite, Professional, Ultimate?

Я парень жесткий, и мне подходит только лицензия WMProtect Ultimate, т.к. только она поддерживает web-генерацию серийных номеров и прочие фенечки, связанные с WLM. WLM написан на PHP и сделан очень толково. Ничего лишнего и все по делу (ИМХО). Короче, нраица. В отличие от ASProtect, на сайте WMProtect достаточно подробная документация представлена только на английском языке, но когда это останавливало пьяных страждущих русских мужиков с цыганами и медведями?

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

Кроме того, в WMProtect реализована функция деактивации лицензии. Такое бывает нужно, когда покупатель просит вернут деньги. В этом случае вы, в свою очередь, просите его деактивировать лицензию, и, если он это делает, возвращаете стоимость программы. А если не делает, то на нет и суда нет. Такая вот простая и действенная защита.

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

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

Щупаем WebLM

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

Как бесплатно пощупать менеджер лицензий (Web License Manager), можно узнать тут (логин: admin и пароль: admin).

Демо-сайт развернут по адресу: http://weblm.vmpsoft.com

Все желающие могут поиграться и оценить функционал, за что разработчикам отдельное спасибо.

Отмечу, что интерфейс переведен на русский, а вот справка только на английском. Да, справка есть и достаточно подробная, хотя она порой не все охватывает. Например, из нее не очевидно, что адрес WLM нужно прописывать в опциях WMProtect. Иначе функции онлайн-регистрации просто не будут работать. Но эта информация есть в справке по WMProtect, что радует. Короче совсем немного не доработали, но это легко исправить.

В конце статьи я выложу пример, в котором будут реализованы все основные функции WMProtect и в частности - активация/деактивация программы через локальный WLM.

Анализ сравнительный и короткий

Как меня учили в институте, сначала нужно сделать сравнительный анализ. Но я это правило, как правило, не выполняю, а зря.

Короче, не буду тут заморачиваться, понятно одно: WMProtect однозначно более функциональный продукт, но он и стоит в несколько раз дороже, чем ASProtect. Но зато он заточен под активацию через интернет, что, на мой взгляд, заслуживает огромного жирного плюса. Лично я однозначно выбираю WMProtect. Дальше даже смотреть не буду, просто время тратить не хочется.

А что о VMProtect говорят хакеры в рунете?

Информация старая, но другой просто не нашел.

Виртуализация кода? Не, не слышал

Ну, значит, сейчас увидишь.

Тут копипаста, чтобы вам не лазить в гугл.

Виртуальная машина, используемая в VMProtect SE, является виртуальным процессором, система команд которого сильно отличается от используемого в х86 компьютерах. Например, в нем нет команд, отвечающих за сравнение двух операндов, нет условных и безусловных переходов.

Во время защиты исполняемого файла VMProtect SE преобразует код программы в байткод своей ВМ и записывает его вместо обычного, не защищенного кода. Он может по-разному обрабатывать защищаемый код в зависимости от выбранного типа компиляции. Рассмотрим подробнее, что из себя представляет каждый тип компиляции:

Мутация. Исполняемый код видоизменяется на уровне команд процессора (существующие команды видоизменяются, добавляются различные мусорные команды и т.д.). Данный тип компиляции слабо защищает обрабатываемый код от взлома и анализа и главным образом препятствует определению обрабатываемых функций с помощью сигнатурных анализаторов (PEiD+KANAL, IDA+FLIRT и т.д.). Как правило, библиотечные функции не нуждаются в защите от взлома и анализа, и достаточно будет только изменить их сигнатуры, чтобы взломщик не смог автоматически определить, какие именно библиотеки Вы используете в своем приложении (степень защиты от взлома и анализа - низкая, скорость исполнения кода - высокая).

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

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

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

А продукты свежие?

Краткую документацию по работе с продуктами можно почитать здесь.

При создании продукта в WLM можно настроить много различных параметров, в число коих входит и количество рабочих мест, на которые распространятся выдаваемый код активации (extra activations). В момент активации VMProtect формирует уникальный идентификатор компьютера (HWID) и передает его на сервер активации, который жестко связывает этот HWID с выданной лицензией. Кроме того, при активации программы с разных компьютеров на сервере увеличивается счетчик выданных лицензий, и если он превышает максимальное значение, то лицензии больше НЕ выдаются, а клиент получает сообщение об ошибке.

Продуктовый импорт

Это очень полезная функция, и именно ей вы должны пользоваться, когда создаете новый продукт в WLM, дабы упростить себе жизнь. Почему? Да потому, что эта замечательная функция сама создаст новый продукт и импортирует все необходимые данные из файла конфигурации VMProtect. Все, что вам останется сделать, - это настроить параметры продукта и поменять его название на осмысленное.

Для каждой защищаемой программы VMProtect создает отдельный файл конфигурации, который имеет расширение vmp. В этом файле хранятся не только параметры и ключи шифрования, но и серийные номера лицензий.

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

Продуктовый экспорт

Данная функция позволяет экспортировать все лицензии, связанные с продуктом, во внешний файл лицензий. Очень удобно для синхронизации лицензий между WLM и основным файлом конфигурации.

Активируй это онлайн

Самая серверная точка

За активацию на сервере отвечает скрипт activation.php. Он принимает всего три параметра. Давайте мельком заглянем под капот:

$res = Activation::Activate($_GET["code"], $_GET["hwid"], $_GET["hash"]);

где:

  • code - код активации;
  • hwid - код оборудования;
  • hash - собственно хэш.

Что еще за хащ такой? Чтобы немного расслабится, можете послушать веселенький тематический трек от рэпера Killagram, а мы... А мы тем временем начнем.

Чтобы разобраться, придется немного покопаться в процедуре регистрации, которая живет в файлике include/activation.inc.php. Открываем. Смотрим. Так, что же нас, собснно, интересует? А вот что:

$p = Product::FromDb($act->productid);
$snattrs = json_decode($p->snattrs, TRUE);
if ($hash != base64_encode(sha1(base64_decode($p->modulus), TRUE)))
    return $ACT_BAD;

Думаю, тут все понятно без лишних комментариев. Если тебе не понятно, тогда иди учи PHP и возвращайся, когда почувствуешь силу. Особое внимание обрати на третью строчку этой абракадабры.

Хочу активации код

Давайте по порядку, господа. Первым делом хоца получить код активации. Ну, дурное дело нехитрое. Для этого устраиваем HTTP GET запрос следующего содержания:

[pre lang=php]%WLM%/keygen.php?keygen.php?productid=%PRODUCT_ID%&customeremail=%CUSTOMER_EMAIL%&customername=%CUSTOMER_NAME%&companyname=%COMPANY_NAME%&quantity=%QUANTITY%&orderref=%ORDER_ID% 

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

Строку запроса нужно прогнать через URLEncode, чтобы ее можно было передать через GET-запрос. Если значения полей не содержат пробелов, то этот шаг можно пропустить.

Отдельного внимания заслуживают поля PRODUCT_ID и ORDER_ID.

Поле PRODUCT_ID должно соответствовать идентификатору продукта, который можно узнать из WLM. Для этого нужно навести курсор мыши на нужный продукт и щелкнуть по ссылке “Keygen URL”.

Если вы укажите неверный PRODUCT_ID, то система сообщит об ошибке.

Поле ORDER_ID формируется агентом электронной коммерции и представляет из себя не что иное как номер заказа. В наших экспериментах ему можно присваивать любое значение.

Если запрос сформирован правильно, то после его выполнения скрипт keygen.php вернет значение кода активации или серийный номер лицензии. Это зависит от того, что указано в настройках продукта в WLM.

Меня интересуют именно коды активации, и поэтому именно эту настройку я указал при создании продукта в WLM. Также можно задать маску, в соответствии с которой будет генерироваться код. По умолчанию она имеет вид ####-####-####. Чтобы упростить парсинг кода, я добавил в маску префикс TEST-.

Приведу несколько примеров “моих” кодов активации:

  • TEST-3NHD-8L3M-VE77;
  • TEST-9963-S2WD-GRSV;
  • TEST-WFNU-3L8J-SHS9.

Хорошо. Код активации получили, а дальше чего?

Чего, чего. Надо его в активатор засовывать. Ну, надо так надо, будем засовывать.

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

Клиент и адрес сервера активации

Тут вроде все просто, если верить документации.

Но в данном конкретном случае документации верить нельзя!

В качестве цитаты приведу важный отрывок текста, который расположен в самом конце страницы:

The address should look as: http://yourserver/weblm path/activate.php

Что в переводе означает: Адрес должен выглядеть так: http://yourserver/weblm path/activate.php

На самом деле адрес должен содержать только путь к вашему серверу лицензий, и все!

Например, если сервер находится у вас на локальной машине, то адрес должен выглядеть так: http://localhost/wlm.

Хочу заметить, что в SDK жестко зашито имя файла скрипта активации activate.php, и его нигде нельзя изменить. Забавно, но это противоречит собственным рекомендациям от VMProtect, изложенным здесь.

Вот, что советуют разработчики:

The www.site.com/keygen.php address is a bad idea. While www.site.com/abc123.php is much better.

Что в переводе означает, что адрес www.site.com/keygen.php - это плохая идея, и лучше использовать адрес www.site.com/abc123.php. Но как это сделать, если у вас в SDK жестко зашит адрес activate.php?

В общем, имейте это в виду.

Хочу лицензии номер серийный

Активатор… Активатор… Где ж тебя взять то?

Так, читаем документейшн... та-па-па-па-пааа, та-та-та-та...

Для начала нужно скопировать в папку с программой (туда, где находится екзешник) пару файлов из VMProtect SDK: VMProtectSDK.dcu и VMProtectSDK32.dll. Если целевая платформа - Win64, то нужно скопировать и VMProtectSDK64.dll.

Затем нужно добавить в проект модуль VMProtectSDK и прописать его в секции uses, которая находится в разделе implementation. Это можно сделать средствами IDE, если нажать комбинацию клавиш ALT+F11 и выбрать соответствующий модуль.

Ага, вот оно:

function VMProtectActivateLicense(ActivationCode: PAnsiChar; Buffer: PAnsiChar; BufferLen: Integer): Integer;

Как видим, нужен сам код активации и буфер для получения серийного номера лицензии. Буфер задействуется только в случае, если код возврата равен нулю.

Информацию по кодам возврата можно почитать здесь.

Размер серийного номера в случае RSA 2048 составляет 345 байт. Это я к тому, какой должен быть размер буфера. Но в примерах используется буфер в 1024 байта.

Ну, теперь дело за малым. Создаем буфер, задаем код активации и выполняем функцию. И как вы думаете, какой будет результат?

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

Танцы с бубенцами

Не буду тянуть кота. Хотя… Ну, пожалуй, совсем чутка.

Когда я предварительно читал документацию, наткнулся на это. Для тех кто в танке - это реализация простенького генератора серийных номеров на PHP. И мой глаз “упал” на раздел “Configuring the generator”, а точнее на следующие параметры:

$exported_algorithm = "RSA";
$exported_bits = 2048;
$exported_private = "PJvj4kEpoQMIpYK+9wEt......xKeiSZgzdiln8Q==";
$exported_modulus = "rOlny/3QgZb/VmGr3CmY......I6ESAUmtQ+RBqQ==";
$exported_product_code = "oLQdGUn8kVk=".

Откуда взяты значения этих параметров? А ответ дается чуть ниже на той же странице.

Оказывается, для каждой защищаемой программы VMProtect создает отдельную конфигурацию, которая хранится в файле с расширением vmp. Чтобы узнать значения рассмотренных выше параметров, нужно открыть этот файл при помощи VMProtect и перейти в форму экспорта ключей через меню “Project -> Export Key Pair…”.

Значения ключей для каждой защищаемой программы всегда будут разные!

Ну, и куда эти параметры засовывать? А засовывать их нужно в одно место, а если быть точнее - в таблицу products. А если еще точнее, то сюда:

$exported_algorithm => products.algorithm;
$exported_private ==> products.private_exp;
$exported_modulus ==> products.modulus;
$exported_product_code ==> products.product_code.

Залезть в эту (да и в другие) табличку вы сможете, если у вас развернут свой WLM. Админка не предоставляет средств редактирования этих параметров, но это можно сделать при помощи PhpMyAdmin. Найти нужный элемент по названию продукта или его номеру труда не составит.

Данные параметры нужно изменить только в корневом элементе продукта, в дочерних ничего менять не нужно. Про дочерние элементы отмечу лишь то, что в WML они называются “Mode”, или модификации, если по-нашему. Тут главное понять, что у всех модификаций параметры, которые мы упомянули выше, должны быть одинаковыми. Другими словами, модификации должны быть реализованы в одном екзешнике.

Ну, тут вроде понятно. Скопировали параметры программы из VMProtect в соответствующие поля таблицы products. Скомпилировали программу из VMProtect. Запускаем и… О, чудо! Функция VMProtectActivateLicense вернула нулевой код, а значит, в переменной Buffer находится серийный номер лицензии. Слава великим бубенцам!

Функции из библиотеки VMProtectSDK будут работать корректно, только если программа скомпилирована при помощи VMProtect. Если запустить программу без этого шага, например, сразу из Delphi, то эти функции будут работать неправильно!

Сказ о HWID

HWID - HardWare Identificator, или уникальный номер компьютера, если по-нашему.

А проблемы подвезли? Конечно подвезли, куда без них. А возникнут они, когда вы поменяете железки в своем суперкомпьютере, а потом решите воспользоваться защищенной софтинкой. Ну, давайте немного подумаем, что тогда будет? Правильно, догадливые вы мои: на новом/модифицированном железе изменится и HWID, а программа жестко с ним связана. Короче, чтобы все было совсем хорошо, нужно будет деактивировать лицензию, а затем ее повторно активировать. Но это не всегда обязательно. Давайте резанем чуть глубже, чтобы получше в этом разобраться.

Эй, Джек. Потрошить будете?

Я немного поразвлекался с HWID, и удалось выяснить, что в базе данных он хранится в виде четырех отдельных цифровых блоков, имеющих разный тип. Можно предположить, что это идентификаторы различных компонентов компьютера.

А давайте препарируем функцию активации и посмотрим на кишочки от первого лица (см. include\activation.inc.php)? Слабознающих SQL и PHP просьба удалится из аудитории, а мы продолжим.

$hwdata = Hwdata::HwidDecode($hwid);
            if (is_array($hwdata) && count($hwdata) > 0)
            {
                $sql = "SELECT licenseid, SUM(value) as c FROM " .
                    "(SELECT DISTINCT h.licenseid, h.type, CASE h.type WHEN 0 THEN 10 ELSE 1 END AS value FROM " .
                    "{$DB_PREFIX}hwdata h LEFT JOIN {$DB_PREFIX}licenses l ON h.licenseid=l.id WHERE " .
                    "l.activationid=" . Sql($act->id) . " AND l.blocked='0' AND h.value IN (" . Sql($hwdata) . ")) as t " .
                    "GROUP BY t.licenseid HAVING c>=12 ORDER BY c DESC LIMIT 1";
                $res = DbQuery($sql);
                if ($res)
                {
                    $l = License::FromDb($res[0]["licenseid"]);
                    if ($l)
                        return $l->sn;
                }
            } 
            else 
                return $ACT_BAD; //Invalid format

Итак, интерны, прошу обратить внимание на фрагмент:

CASE h.type WHEN 0 THEN 10 ELSE 1 END AS value;

Петров, есть соображения? Что глаза вытаращил? Я же попросил всех слабознающих удалится!

Ну хорошо, хорошо, слушать сюда, любознательные вы мои.

Первый фрагмент сигнализирует нам о том, что тип железяки имеет вес, а если точнее, то железки с типом ноль весят 10 хардвариков, а все остальные только один. Из этого можно предположить, что под кодом 10 подразумевается материнка или винт.

Так, давайте запустим ручонки немного глубже в кишочки. Ага, кажется, нащупал… Так, так, что это?

GROUP BY t.licenseid HAVING c>=12 ORDER BY c DESC LIMIT 1.

Вот оно значит как! Если сумма типов всех железок больше или равна 12 хардвариков, то алгоритм считает, что с железом все нормально, и можно не выполнять повторную активацию программы.Это всем понятно? Хорошо, тогда поехали дальше.

Сделаем еще один глубокий надрез при помощи хорошо заточенного PhpMyAdmin и посмотрим на данные, которые хранятся в таблице hwdata:

ID LICENSEID TYPE VALUE
18 3 0 3259634028
19 3 1 2891921801
20 3 3 836435399
21 3 2 3315951650

Теперь посчитаем сумму полей в колонке TYPE, используя вышеразжеванные правила. Так, и что получается? Иванов? Шесть? Эх… Я же сказал использовать правила! Садись, умник.

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

Послепотрошительные выводы

Ну, в-первых, теперь стало понятно, что если заменить второстепенную железку, то повторная активация будет использовать ту же лицензию.

Во-вторых, теперь мы можем самостоятельно изменить алгоритм активации. Если уменьшить значение в условии отбора с 12 на 10, то уменьшится строгость соответствия HWID, и пользователь сможет заменить сразу несколько устройств одновременно без необходимости деактивации и повторной активации программы.

Задание. Домашнее задание

Честно говоря, мне было лень проверять, как работает алгоритм проверки HWID на клиенте (без подключения к интернету). Исходников SDK у меня нет (возможно, их вообще нет), поэтому призываю энтузиастов разобраться, как себя ведет защищенная программа при смене/установке/удалении железок. Также хочется понять, каким железкам соответствуют типы в таблице hwdata.

Что-то мне подсказывает, что на клиенте выполняется проверка на полное соответствие HWID, и при замене оборудования активация потребуется обязательно. Тому, кто это подтвердит (или опровергнет), я лично выражу благодарность, отправив пустое электронного письмо с жалобой в Администрацию Президента Российской Федерации.

Де3активируй это онлайн

Активация это хорошо, но де3активация еще лучше, особенно если в это слово добавить цифру “3” ;)

Во-первых, это пригодится в случаях, когда клиент хочет вернуть деньги. Ну, не понравился ему ваш говносовфт, а вы дали гарантию возврата денег. Если вы порядочный гомосапиенс, то обязательства придется выполнять. Но в договоре нужно непременно указать, что условием возврата кровно заработанных является деактивация лицензии через интернет. Кроме того, как я уже писал выше, это обломает мошенников, которые хотят и рыбку съесть, и тараканов поморить.

Основная идея деактивации в том, что в любой момент можно освободить свою лицензию (если есть доступ к WLM). При этом ранее выданная вам лицензия блокируется. Даже если вы сразу после деактивации повторно активируете программу, вам будет выдана уже другая лицензия, а предыдущая останется заблокированной. Вероятно, таким образом в VMProtect реализован механизм плавающих лицензий.

Серверная часть

Точкой входа является скрипт deactivation.php. Имя файла жестко зашито в SDK, и поменять его никак низя (насколько я знаю). Как отключить механизм деактивации через админку, я найти не смог. Самым простой и очевидный способ это сделать - удалить или переименовать файл deactivation.php. Но если посмотреть коды возврата функции VMProtectDeactivateLicense, которая отвечает за онлайн деактивацию лицензий, то где-то на сервере должна быть возможность отключения деактивации (см. ACTIVATION_NOT_AVAILABLE). Мои поиски по скриптам сервера не дали ответа на этот вопрос. Мне лишь удалось выяснить, что функция деактивации на сервере в качестве результата возвращает следующие константы (см. include\activation.inc.php):

$DEACT_OK = "OK";
$DEACT_ERROR = "ERROR";
$DEACT_UNKNOWN = "UNKNOWN";

Из этого можно заключить, что самый очевидный способ на данный момент является самым простым и правильным. Возможно, данную недоработку исправят (или уже исправили) в следующей версии WLM. Теперь подробно рассмотрим, какие параметры принимает скрипт деактивации. Начнем с содержимого файла deactivation.php. В 12 строке видим:

if (empty($_GET["hash"]))

Видимо, в скрипт деактивации передается хэш серийного номера.

Ладно. Копнем еще глубже. Для этого открываем файл include\activation.inc.php и в 135 строке видим:

$res = ObjectsSqlLoad("SELECT * FROM {$DB_PREFIX}licenses WHERE snhash=" . Sql($snhash), "License");

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

Напомню, что при деактивации лицензии счетчик свободных лицензий, связанный с кодом активации, увеличивается.

Теперь давайте разберемся, как формируется этот самый хэш.

Лезем в include\license.inc.php и в строке 325 видим:

$this->snhash = base64_encode(sha1(base64_decode($this->sn), TRUE));

Ну вот вам, собственно, и ответ. Хочу только заметить, что серийный номер предварительно декодируется, а это значит, что он хранится в base64-кодировке.

Клиентская часть

Ну, тут уже вроде как по накатанной. Давайте посмотрим, что там у нас в SDK. Так, так, так… Ага, вот она родимая:

function VMProtectDeactivateLicense(SerialNumber: PAnsiChar): Integer;

Как несложно догадаться, в качестве параметра эта функция принимает код активации.

Информацию по кодам возврата можно почитать здесь. Но как можно понять из предыдущей главы, в данном случае используется только три кода.

А что будет, если код активации заблокирован? Рассмотрим этот вопрос поподробнее, т.к. поведение здесь не совсем очевидное.

Во-первых, при блокировке кода активации лицензии, которые выдавались по этому коду, не блокируются.

Во-вторых, при вызове процедуры деактивации с указанием заблокированного кода активации соответствующая лицензия тоже будет заблокирована! Повторная активация лицензии будет недоступна.

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

Сделай это через “подружку”

В этой главе речь пойдет от активации или деактивации лицензии, если на вашем компьютере нет подключения к интернету. Да да, умные разработчики из VMProtect предусмотрели и такую возможность, но для этого вам понадобится подружка, у которой есть доступ в интернет. Давайте более подробно рассмотрим, как эти функции использовать.

Активация через “подружку”

Ну, давайте снова заглянем в SDK. Так, ага… Вот она:

function VMProtectGetOfflineActivationString(ActivationCode: PAnsiChar; Buffer: PAnsiChar; BufferLen: Integer): Integer;

На первый взгляд вроде все опять понятно. Передаем в функцию серийный номер лицензии и буфер. В документации рекомендуют, чтобы длина буфера была не менее 1000 байт. Ну, рекомендуют, значит, так сделаем. Информацию по кодам возврата снова можно почитать здесь.

Но сразу возникает резонный вопрос: а чо и куда надо вводить? Сейчас, сейчас, нетерпеливые вы мои, все по порядку.

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

В ответ WLM выдаст серийный номер лицензии (или сообщение об ошибке). Серийный номер нужно сохранить и затем ввести на исходной локальной машине в защищенную программу.

А теперь по традиции будем смотреть кишочки файла offline.php.

Сестра, подайте notepad++, будем редактировать… Так-так…ага... Очень интересно.

Итак, интерны, прошу вас обратить внимание на строчку 17:

$args = explode("&", base64_decode($url));

В ней выполняется base64-декодирование, а затем и парсинг введенного в форму значения. Хочу напомнить, что это значение было сгенерировано функцией VMProtectGetOfflineActivationString.

Это понятно. Теперь осторожно… осторожно ведем курсор до строки 28, пока не появится строка:

elseif ($type == "activation")

И что же это значит? А то, что в переменной $url передаются не только данные, но и тип выполняемой операции. Подтверждение наших слов находится в строке 35:

elseif ($type == "deactivation")

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

Ну, и чтобы клиническая картина стала совсем полной, обратим взор на строку 30:

if (empty($code) || empty($hwid) || empty($hash))

В ней прямым кодом написано, что переменная $url кроме параметра type может содержать параметры code, hwid и hash.

При активации программы параметры передаются методу активации, расположенному в строке 33:

$res = Activation::Activate($code, $hwid, $hash)

Более подробно процедуру активации я рассматривал выше, в главе Активируй это онлайн, а все, кто записывал, могут полистать конспекты.

Ну вот, пожалуй пока и достаточно, можно закрывать файл, но без сохранения!

Перерыв 5 минут.

Де3активация через подружку

Не буду тут размусоливать. Вот объявление функции:

function VMProtectGetOfflineDeactivationString(SerialNumber: PAnsiChar; Buffer: PAnsiChar; BufferLen: Integer): Integer;

Параметры уже привычные: серийный номер и буфер. Размер буфера не менее 1000 байт. Информацию по кодам возврата снова смотрим здесь.

Если функция отработала успешно, то код возврата будет равен нулю, а в буфере будет набор символов, который нужно сохранить и потом ввести на странице %WLM%/offline.php с компьютера подружки.

В переменной буфера содержится всего два закодированных base64-параметра: type и hash. Параметр type должен быть равен "deactivation", а параметр hash мы подробно рассматривали в главе Де3активируй это онлайн.

Накропаем VMProtectTestoTron.dpr

После установки WMProtect он накидает на ваш винт свои примерчики. Лежат они в папочке %DRIVE%:\Users\%USER_NAME%\Documents\VMProtect. Рекомендовано к прочтению. Но в них нет примеров работы с WLM, что, кстати, очень зря. Я этот пробел восполню и, конечно, все вам разжую в питательную и понятную интеллектуальную кашицу smile

Я использую Delphi 10.1 Berlin. Все используемые компоненты базовые (TLabel, TEdit, TButton, TidHTTP), поэтому пример должен запустится и на старых версия Delphi (но это неточно).

Специально для тестирования рекомендую выполнить следующие шаги:

  1. В целях ознакомления скачать VMProtect здесь;
  2. Скачать xampp и развернуть локальный веб-сервер в директорию C:\XAMPP;
  3. В директорию C:\XAMPP\HTDOCS\WLM скопировать содержимое дистрибутива WebLM;
  4. Скачать исходники VMProtectTestoTron (на Delphi) здесь.

Для любителей посмотреть видео я специально выложил на ютубе подробную инструкцию с комментариями:

© By KAA aka Alexey Kryukov

Оставьте комментарий!

Используйте нормальные имена

Вы можете войти под своим логином или зарегистрироваться на сайте.

(обязательно)