first commit

Version 3.x.x
This commit is contained in:
VNGhostMans
2023-05-14 20:21:09 +07:00
parent a3037a8db3
commit 5ec92ee05e
1166 changed files with 1036539 additions and 0 deletions

View File

@@ -0,0 +1,312 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Описание функций API лицензирования</title>
<style type="text/css">
/*<![CDATA[*/
th {text-align:left;}
table {border-collapse:collapse; margin-top: 4px;}
td,th {border: 1px solid #B0B0B0; padding-left:10;padding-right:10;}
/*]]>*/
</style>
</head>
<body>
<h1>Описание функций API лицензирования</h1>
<p>API системы лицензирования является продолжением API VMProtect
и входит в его SDK. API позволяет задать серийный номер и
получить информацию о нем: подходит он к программе или нет, истек
ли срок действия, на кого зарегистрирован продукт и т.п. Также API
позволяет получить идентификатор оборудования, на котором
выполняется программа.</p><strong id=
"VMProtectSetSerialNumber">VMProtectSetSerialNumber</strong>
<p>Функция предназначена для загрузки серийного номера в систему
лицензирования. Полный формат вызова представлен ниже:</p>
<pre class="code">int VMProtectSetSerialNumber(const char *SerialNumber);
</pre>
<p>Входной параметр <strong>SerialNumber</strong> должен
содержать указатель на текстовую строку с серийным номером в
кодировке base-64 и завершаемую нулем ('\0'). Функция возвращает
битовую маску флагов состояния серийного номера, аналогичную той,
что возвращает <strong>VMProtectGetSerialNumberState()</strong>,
подробнее о флагах будет написано ниже. Серийный номер считается
"хорошим", если функция вернула значение 0.</p><br />
<strong id=
"VMProtectGetSerialNumberState">VMProtectGetSerialNumberState</strong>
<p>Функция возвращает флаги состояния серийного номера,
предварительно установленного вызовом
<strong>VMProtectSetSerialNumber()</strong>.</p>
<pre class="code">int VMProtectGetSerialNumberState();
</pre>
<p>Наличие хотя бы одного установленного флага говорит о
проблемах с серийным номером: программа не должна работать, если
установлен хотя бы один бит. Подробные значениях флагов описаны в
таблице:</p>
<table border="1" cellspacing="0" cellpadding="2">
<tr>
<th>Флаг</th>
<th>Значение</th>
<th>Описание</th>
</tr>
<tr>
<td>SERIAL_STATE_FLAG_CORRUPTED</td>
<td>0x00000001</td>
<td>Система лицензирования повреждена. Возможные причины:
некорректная настройка проекта защиты, попытка взлома
программы.</td>
</tr>
<tr>
<td>SERIAL_STATE_FLAG_INVALID</td>
<td>0x00000002</td>
<td>Серийный номер некорректен. Флаг выставляется, если
система лицензирования не может расшифровать серийный
номер.</td>
</tr>
<tr>
<td>SERIAL_STATE_FLAG_BLACKLISTED</td>
<td>0x00000004</td>
<td>Серийный номер подходит к продукту, однако занесен в
черный список в VMProtect.</td>
</tr>
<tr>
<td>SERIAL_STATE_FLAG_DATE_EXPIRED</td>
<td>0x00000008</td>
<td>Срок действия серийного номера истек. Подробную
информацию о сроке действия можно получить вызовом
<strong>VMProtectGetSerialNumberData()</strong></td>
</tr>
<tr>
<td>SERIAL_STATE_FLAG_RUNNING_TIME_OVER</td>
<td>0x00000010</td>
<td>Время работы программы истекло. Подробную информацию о
времени работы программы можно получить вызовом
<strong>VMProtectGetSerialNumberData()</strong></td>
</tr>
<tr>
<td>SERIAL_STATE_FLAG_BAD_HWID</td>
<td>0x00000020</td>
<td>Идентификатор оборудования не совпадает с тем, что
записан в серийном номере.</td>
</tr>
<tr>
<td>SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED</td>
<td>0x00000040</td>
<td>Серийный номер не предназначен для работы с этой версией
защищаемой программы. Максимальную дату сборки программы, к
которой подходит этот серийный номер, можно узнать вызовом
<strong>VMProtectGetSerialNumberData()</strong>.</td>
</tr>
</table><br /><br />
<strong id=
"VMProtectGetSerialNumberData">VMProtectGetSerialNumberData</strong>
<p>Функция предназначена для получения информации о содержимом
серийного номера, установленного вызовом
<strong>VMProtectSetSerialNumber()</strong>. Формат вызова
представлен ниже:</p>
<pre class="code">bool VMProtectGetSerialNumberData(VMProtectSerialNumberData *Data, int Size);
</pre>
<p>Первый параметр - указатель на структуру
<strong>VMProtectSerialNumberData</strong>, в которую будет
записана вся необходимая информация. Второй параметр - размер
структуры, передаваемой в первом параметре - служит для контроля
формата структуры. Функция возвращает FALSE в случаях, если система
лицензирования повреждена (см. флаг состояния
SERIAL_STATE_FLAG_CORRUPTED), если на вход подан нулевой адрес
структуры или если переданный размер структуры некорректен. Во
всех остальных случаях функция возвращает TRUE и записывает всю
информацию о серийном номере по указанном адресу. Ниже
описываются все элементы структуры:</p>
<table border="1" cellspacing="0" cellpadding="2">
<tr>
<th>Элемент</th>
<th>Тип</th>
<th>Описание</th>
</tr>
<tr>
<td>nState</td>
<td>int</td>
<td>Битовая маска флагов проверки ключа. Аналогична той, что
возвращает
<strong>VMProtectGetSerialNumberState()</strong>.</td>
</tr>
<tr>
<td>wUserName</td>
<td>wchar_t[256]</td>
<td>Имя покупателя в кодировке UNICODE, завершаемое
нулем.</td>
</tr>
<tr>
<td>wEMail</td>
<td>wchar_t[256]</td>
<td>E-Mail покупателя в кодировке UNICODE, завершаемый
нулем.</td>
</tr>
<tr>
<td>dtExpire</td>
<td>VMProtectDate</td>
<td>Дата окончания срока действия ключа. Формат структуры
VMProtectDate описан ниже.</td>
</tr>
<tr>
<td>dtMaxBuild</td>
<td>VMProtectDate</td>
<td>Максимальная дата сборки продукта, с которой будет
работать этот ключ. Формат структуры VMProtectDate описан
ниже.</td>
</tr>
<tr>
<td>bRunningTime</td>
<td>int</td>
<td>Количество минут, которое программа будет работать
(максимальная длина сессии). Измеряется в минутах,
отсчитывается с момента запуска программы.</td>
</tr>
<tr>
<td>nUserDataLength</td>
<td>unsigned char</td>
<td>Длина пользовательских данных, размещенных в поле
<strong>bUserData</strong>.</td>
</tr>
<tr>
<td>bUserData</td>
<td>unsigned char[255]</td>
<td>Пользовательские данные, записанные в ключ. Количество
актуальных байт указано в поле
<strong>nUserDataLength</strong>.</td>
</tr>
</table><br />
<p>Структура <strong>VMProtectDate</strong> предназначена для
компактного хранения даты. Ее поля описаны в таблице:</p>
<table border="1" cellspacing="0" cellpadding="2">
<tr>
<th>Элемент</th>
<th>Тип</th>
<th>Описание</th>
</tr>
<tr>
<td>wYear</td>
<td>unsigned short</td>
<td>Год.</td>
</tr>
<tr>
<td>bMonth</td>
<td>unsigned char</td>
<td>Месяц, нумерация начинается с единицы.</td>
</tr>
<tr>
<td>bDay</td>
<td>unsigned char</td>
<td>День, нумерация начинается с единицы.</td>
</tr>
</table><br />
<br />
<strong id=
"VMProtectGetCurrentHWID">VMProtectGetCurrentHWID</strong>
<p>Функция предназначена для получения идентификатора
оборудования, на котором работает программа. Формат вызова
следующий:</p>
<pre class="code">int VMProtectGetCurrentHWID(char * HWID, int Size);
</pre>
<p>Первый параметр - указатель на область памяти, куда будет
записан идентификатор. Второй параметр - размер области данных.
Функция возвращает количество записанных байт с учетом
завершающего нуля ('\0'). Если вместо первого параметра подать
NULL, то функция вернет необходимое количество байт для записи
номера. Наиболее правильный способ вызова функции следующий:</p>
<pre class="code"><strong>int</strong> nSize = <strong>VMProtectGetCurrentHWID</strong>(NULL, 0); // получим необходимый размер буфера
<strong>char *</strong>pBuf = <strong>new char</strong>[nSize]; // выделим буфер
<strong>VMProtectGetCurrentHWID</strong>(pBuf, nSize); // получим идентификатор
// используем его
<strong>delete</strong> [] pBuf; // освободим память
</pre><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,127 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Интеграция в приложение</title>
<style type="text/css">
</style>
</head>
<body>
<h1>Интеграция в приложение</h1>
<p>В нескольких шагах, описанных ниже, мы создадим тестовое
приложение, которое будет обращаться к системе лицензирования:
подавать ей серийные номера и получать статус номера и его
содержимое. На первом этапе система лицензирования будет
использоваться в тестовом режиме, а на втором этапе - в
реальном.</p><strong>Режимы работы системы
лицензирования</strong>
<p>В создании защиты всегда есть два этапа: разработка и
использование. В случае с лицензированием, вы сначала создаете
приложение, потом интегрируете механизмы защиты, добавляете
проверки и блокируете функции. И только потом, после
всестороннего тестирования, продукт передается пользователям и
начинается второй этап. Тестирование защищаемого приложения -
процесс сложный, необходимо убедиться в работоспособности всех
проверок и условных переходов. Создание "настоящих" серийных
номеров на все случаи жизни на этапе тестирования может оказаться
неудобным, поэтому у системы лицензирования есть т.н. "режим
разработки" или "тестовый" режим, при котором никакой защиты не
осуществляется, а реакция системы на серийные номера описывается
в конфигурационном файле. Когда приложение отлажено и корректно
работает с системой лицензирования, VMProtect заменяет "тестовый"
модуль лицензирования на реальный, проверяющий реальные серийные
номера. Это происходит в момент защиты приложения, поэтому
пропустить этот этап по ошибке не получится.</p><strong id="TestMode">Этап 1:
Тестовый режим работы</strong>
<p>В тестовом режиме реакция системы лицензирования на серийные
номера, все возвращаемые статусы и данные описываются в
конфигурационном файле. Файл называется VMPLicense.ini и должен
располагаться в рабочем каталоге приложения. В 10 шагах,
представленных ниже, мы пройдем от создания простейшего
приложения до полноценного использования системы лицензирования в
тестовом режиме с привязкой к оборудованию и ограничением срока
бесплатных обновлений.</p>
<ul>
<li><a href="step11_app.htm">Шаг 1.1: Создаем защищаемое
приложение</a></li>
<li><a href="step12_code.htm">Шаг 1.2: Добавляем код проверки
лицензии</a></li>
<li><a href="step13_flags.htm">Шаг 1.3: Получаем флаги состояния
номера</a></li>
<li><a href="step14_name.htm">Шаг 1.4: Получаем имя и e-mail
пользователя</a></li>
<li><a href="step15_exp.htm">Шаг 1.5: Проверяем срок действия
номера</a></li>
<li><a href="step16_time.htm">Шаг 1.6: Ограничиваем время работы
программы</a></li>
<li><a href="step17_maxbuild.htm">Шаг 1.7: Ограничиваем
бесплатные обновления</a></li>
<li><a href="step18_blacklist.htm">Шаг 1.8: Номера из "черного
списка"</a></li>
<li><a href="step19_hwid.htm">Шаг 1.9: Привязка к
оборудованию</a></li>
<li><a href="step1A_userdata.htm">Шаг 1.10: Пользовательские
данные</a></li>
</ul><strong id="RealMode">Этап 2: Реальный режим работы</strong>
<p>В реальном режиме работы системы лицензирования VMProtect
помещает в защищаемое приложение специальный модуль
лицензирования. Модуль выполняет все те же функции, что и
тестовый код в SDK, но работает не с ini-файлом, а с содержимым
серийного номера. В следующих пяти шагах мы защитим простое
приложение полноценной защитой на основе VMProtect и системы
лицензирования.</p>
<ul>
<li><a href="step21_src.htm">Шаг 2.1: Создаем новое защищаемое
приложение</a></li>
<li><a href="step22_vmp.htm">Шаг 2.2: Создаем проект защиты в
VMProtect</a></li>
<li><a href="step23_product.htm">Шаг 2.3: Первый запуск
защищенного продукта</a></li>
<li><a href="step24_test.htm">Шаг 2.4: Тестируем
результат</a></li>
<li><a href="step25_codelock.htm">Шаг 2.5: Привязываем код к
серийному номеру</a></li>
</ul><strong>Дополнительная информация</strong>
<p>Значения всех битовых флагов, форматы структур и параметры
вызова функций можно посмотреть в разделе <a href="api.htm">API
системы лицензирования</a>. Этот раздел удобно использовать как
справочник, тогда как шаги, описанные выше, позволяют легко
реализовать готовые типовые схемы защиты.</p><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,62 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 1.1: Создаем защищаемое приложение</title>
</head>
<body>
<h1>Шаг 1.1: Создаем защищаемое приложение</h1>
<p>Первым шагом будет создание приложения. Это будет простое
приложение, без интерфейса пользователя и каких-либо серьезных
возможностей. Нашей задачей будет передать системе лицензирования
серийный номер и получить от нее ответ.</p>
<pre class="code">#include &lt;windows.h&gt;
#include &lt;stdio.h&gt;
bool is_registered(const char *serial)
{
return serial &amp;&amp; serial[0] == 'X';
}
int main(int argc, char **argv)
{
char *serial = "Xserialnumber"; // зададим номер непосредственно в коде для простоты
if (!is_registered(serial))
{
printf("please register!\n");
return 0;
}
printf("We are registered.\n");
return 0;
}
</pre>
<p>Программа реализует очень простую схему проверки серийного
номера. Функция <strong>is_registered()</strong> сравнивает
первую букву номера с 'Х' и считает номер корректным в случае
совпадения. Для некорректного номера выдается просьба о
регистрации, а в случае правильного номера выводится сообщение
"We are registered."</p>
<p><a href="step12_code.htm">Следующим шагом</a> будет добавление
кода проверки серийного номера на основе системы лицензирования
VMProtect.</p><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,105 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 1.2: Добавляем код проверки лицензии</title>
</head>
<body>
<h1>Шаг 1.2: Добавляем код проверки лицензии</h1><strong>Подключаем
VMProtect SDK</strong>
<p>Если вы этого еще не сделали, то сейчас самое время подключить
к проекту VMProtect SDK. SDK это три файла: заголовочный файл
(VMProtectSDK.h), файл библиотеки (VMProtectSDK32.lib) и dll-файл
с реализацией (VMProtectSDK32.dll). Для 64-битной платформы есть
отдельные реализации библиотеки и dll-файла.</p>
<p>Помещаем dll-файл в рабочий каталог нашего приложения,
файл заголовков и библиотечный файл - рядом с исходниками, включаем
файл заголовков в основной файл:</p>
<pre class="code">#include &lt;windows.h&gt;
#include &lt;stdio.h&gt;
#include "VMProtectSDK.h"
</pre>
<p>Собираем проект и убеждаемся, что он компилируется, запускается
и работает, как и раньше. Система лицензирования пока еще не
активна.</p><strong>Подаем серийный номер в систему
лицензирования</strong>
<p>Теперь непосредственно после строки с серийным номером добавим
вызов функции SDK системы лицензирования:</p>
<pre class="code">char *serial = "Xserialnumber"; // зададим номер непосредственно в коде для простоты
int res = VMProtectSetSerialNumber(serial);
printf("res = 0x%08X\n", res);
</pre>
<p>Если после этого программа будет завершаться с ошибкой об
отсутствии dll-файла, убедитесь, что вы положили соответствующий
DLL-файл в рабочий каталог нашего приложения. В случае успешного
запуска, вы должны увидеть сообщение:</p>
<pre class="code">res = 0x00000002
</pre>
<p>Число 2 соответствует флагу SERIAL_STATE_FLAG_INVALID,
<a href="api.htm">описанному в API</a>. Т.е. система
лицензирования посчитала наш ключ некорректным, что вполне
логично, т.к. мы до сих пор не "объяснили" системе лицензирования,
какие ключи считать правильными, а какие - нет.</p><strong>Задаем
"правильный" серийный номер</strong>
<p>В тестовом режиме система лицензирования анализирует файл
VMProtectLicense.ini, и реагирует на вызовы функций согласно
указанным там настройкам. Подробно файл разбирается в следующих
шагах, а здесь мы просто создадим такой файл и поместим туда
следующий текст:</p>
<pre class="code">[TestLicense]
AcceptedSerialNumber=Xserialnumber
</pre>
<p>Запустим нашу программу еще раз. Если вы снова получили код
ошибки "2", то убедитесь, что ini-файл находится в рабочем
каталоге приложения. В этот раз вы должны получить результат "0".
Признак того, что система лицензирования приняла и одобрила
серийный номер. Теперь мы можем убрать функцию
<strong>is_registered()</strong> - проверкой серийного номера
займется система лицензирования:</p>
<pre class="code">#include &lt;windows.h&gt;
#include &lt;stdio.h&gt;
#include "VMProtectSDK.h"
int main(int argc, char **argv)
{
char *serial = "Xserialnumber"; // зададим номер непосредственно в коде для простоты
int res = VMProtectSetSerialNumber(serial);
printf("res = 0x%08X\n", res);
if (res)
{
printf("please register!\n");
return 0;
}
printf("We are registered.\n");
return 0;
}
</pre><br />
<a href="step13_flags.htm">Следующий шаг</a>
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,96 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 1.3: Получаем флаги состояния серийного номера</title>
</head>
<body>
<h1>Шаг 1.3: Получаем флаги состояния серийного
номера</h1><strong>Удобная функция для печати флагов</strong>
<p>Первым делом добавим в наш файл одну удобную функцию, которая
будет печатать в человеческом виде значения флагов состояния
серийного номера. Код функции приведен ниже:</p>
<pre class="code">#define PRINT_HELPER(state, flag) if (state &amp; flag) printf("%s ", #flag)
void print_state(INT state)
{
if (state == 0)
{
printf("state = 0\n");
return;
}
printf("state = ");
PRINT_HELPER(state, SERIAL_STATE_FLAG_CORRUPTED);
PRINT_HELPER(state, SERIAL_STATE_FLAG_INVALID);
PRINT_HELPER(state, SERIAL_STATE_FLAG_BLACKLISTED);
PRINT_HELPER(state, SERIAL_STATE_FLAG_DATE_EXPIRED);
PRINT_HELPER(state, SERIAL_STATE_FLAG_RUNNING_TIME_OVER);
PRINT_HELPER(state, SERIAL_STATE_FLAG_BAD_HWID);
PRINT_HELPER(state, SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED);
printf("\n");
}
</pre>
<p>Несмотря на свой размер, функция очень простая - она
последовательно проверяет все битовые флаги и печатает те, что
присутствуют в переменной состояния. Заменим
<strong>printf</strong> после проверки номера на вызов
<strong>print_state</strong>, заодно временно поправим серийный
номер, который подается в систему лицензирования:</p>
<pre class="code">char *serial = "Xserialnumber1"; // зададим номер непосредственно в коде для простоты
int res = VMProtectSetSerialNumber(serial);
print_state(res);
</pre>
<p>Если запустить эту программу, то на консоль выведется
следующее:</p>
<pre class="code">state = SERIAL_STATE_FLAG_INVALID
please register!
</pre>
<p>Вернем теперь старый серийный номер, убрав "1", и запустим
программу еще раз:</p>
<pre class="code">state = 0
We are registered.
</pre>
<p>Теперь, когда мы можем видеть флаги состояние серийного
номера, перейдем к получению флагов и данных из серийного
номера.</p><strong>Получение состояния номера</strong>
<p>Состояние номера можно получить тремя способами: вызвав
<strong>VMProtectSetSerialNumber()</strong>, вызвав
<strong>VMProtectGetSerialNumberState()</strong> и вызвав
<strong>VMProtectGetSerialNumberData()</strong> - флаги состояния
будут помещены в одно из полей структуры. Каждый из методов
предназначен для использования в разное время. Первая проверка
серийного номера происходит непосредственно при его установке. В
этот момент нужно отсекать некорректные номера, номера с истекшим
сроком действия, номера из черного списка и т.п. Некоторые
ограничения - скажем, максимальное время работы продукта или срок
действия номера, имеет смысл проверять и в процессе работы
программы. Тут оптимально воспользоваться простым и быстрым
методом <strong>VMProtectGetSerialNumberState()</strong>, а в
случае, если нужно получить подробную информацию о данных в
серийном номере, можно использовать более мощную функцию
<strong>VMProtectGetSerialNumberData()</strong>.</p><br />
<a href="step14_name.htm">Следующий шаг</a>
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,53 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 1.4: Получаем имя и e-mail пользователя</title>
</head>
<body>
<h1>Шаг 1.4: Получаем имя и e-mail пользователя</h1>
<p>Начнем с простого: получим из серийного номера имя и e-mail
пользователя (часто показываются в окне About). Для этого нам
придется прописать их в ini-файл. Добавим еще две строчки к нашим
двум:</p>
<pre class="code">[TestLicense]
AcceptedSerialNumber=Xserialnumber
UserName=John Doe
EMail=john@doe.com
</pre>
<p>А в самой программе, в случае успешной регистрации, добавим
получение этих данных и вывод их на экран:</p>
<pre class="code">VMProtectSerialNumberData sd = {0};
VMProtectGetSerialNumberData(&amp;sd, sizeof(sd));
printf("name = %ls,\ne-mail = %ls\n", sd.wUserName, sd.wEMail);
</pre>
<p>Структура содержит данные в UNICODE, поэтому в
<strong>printf()</strong> использованы спецификаторы %ls вместо %s.
Программа должна вывести на экран текст:</p>
<pre class="code">state = 0
We are registered.
name = John Doe,
e-mail = john@doe.com
</pre><br />
<a href="step15_exp.htm">Следующий шаг</a>
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,59 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 1.5: Проверяем срок действия серийного номера</title>
</head>
<body>
<h1>Шаг 1.5: Проверяем срок действия серийного номера</h1>
<p>Поместите в ini-файл строчку вида ExpDate=YYYYMMDD - например,
такую:</p>
<pre class="code">ExpDate=20000101
</pre>
<p>Важно, чтобы дата, указанная в строке, уже прошла. Т.е.
максимум - вчера. Запустив программу, вы увидите следующее:</p>
<pre class="code">state = SERIAL_STATE_FLAG_DATE_EXPIRED
please register!
</pre>
<p>Добавим получение дополнительной информации перед выходом с
сообщением "please register":</p>
<pre class="code">if (res)
{
VMProtectSerialNumberData sd = {0};
VMProtectGetSerialNumberData(&amp;sd, sizeof(sd));
printf("exp. date: y = %d, m = %d, d = %d\n", sd.dtExpire.wYear, sd.dtExpire.bMonth, sd.dtExpire.bDay);
printf("please register!\n");
return 0;
}
</pre>
<p>Повторный запуск приложения даст нам больше подробностей:</p>
<pre class="code">state = SERIAL_STATE_FLAG_DATE_EXPIRED
exp. date: y = 2000, m = 1, d = 1
please register!
</pre>
<p>Удалите из ini-файла строку ExpDate=..., чтобы она не мешала
нам в дальнейшем.</p><br />
<a href="step16_time.htm">Следующий шаг</a>
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,79 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 1.6: Ограничиваем время работы программы</title>
</head>
<body>
<h1>Шаг 1.6: Ограничиваем время работы программы</h1>
<p>Вы можете ограничить время работы программы с момента запуска.
Это может быть полезно для демонстрационных целей: выдается
полноценный серийный номер, однако программа работает не более
пяти минут. Система лицензирования не закрывает такую программу
принудительно по истечении указанного времени, а лишь уведомляет
об окончании времени выставлением флага состояния. Зададим
ограничение времени работы в одну минуту, добавив в ini-файл
строчку:</p>
<pre class="code">TimeLimit=1
</pre>
<p>Модифицируем программу следующим образом:</p>
<pre class="code">int main(int argc, char **argv)
{
char *serial = "Xserialnumber"; // зададим номер непосредственно в коде для простоты
int res = VMProtectSetSerialNumber(serial);
print_state(res);
if (res) return 0;
VMProtectSerialNumberData sd = {0};
VMProtectGetSerialNumberData(&amp;sd, sizeof(sd));
printf("I will run for %d minute(s)\n", sd.bRunningTime);
print_state(VMProtectGetSerialNumberState());
Sleep(60 * 1000 * sd.bRunningTime);
printf("After %d minute(s):\n", sd.bRunningTime);
print_state(VMProtectGetSerialNumberState());
return 0;
}
</pre>
<p>Программа выводит состояние серийного номера в момент старта,
потом считывает максимальное время работы, ждет, пока оно пройдет
и выводит состояние номера еще раз. Для одной минуты мы получим
следующий результат:</p>
<pre class="code">state = 0
I will run for 1 minute(s)
state = 0
After 1 minute(s):
state = SERIAL_STATE_FLAG_RUNNING_TIME_OVER
</pre>
<p>Защищаемая программа должна анализировать состояние серийного
номера с определенной периодичностью и завершить свою работу в
случае появления такого флага. Система лицензирования не делает
этого автоматически, т.к. программе может требоваться освободить
какие-то ресурсы, записать данные в файл и т.д. Также программа
может не завершаться по истечении данного времени, а переходить в
более ограниченный режим работы. Система лицензирования оставляет
эти вопросы на усмотрение разработчика.</p><br />
<a href="step17_maxbuild.htm">Следующий шаг</a>
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,85 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 1.7: Ограничиваем бесплатные обновления</title>
</head>
<body>
<h1>Шаг 1.7: Ограничиваем бесплатные обновления</h1><strong>Схема
работы</strong>
<p>В момент защиты приложения VMProtect запоминает дату, когда это
происходило. Эта дата является для системы лицензирования датой
сборки приложения. В серийном номере можно прописать максимальную
дату сборки, для которой подойдет этот номер. Таким образом, если
при создании ключа Вы пропишете в него текущую дату + 1 год, то
ключ подойдет ко всем релизам Вашей программы, которые вы
выпустите в течение года. К релизу, выпущенному через год и 1
день ключ уже не подойдет и у пользователя будет выбор:
пользоваться более старой версией или купить новый ключ, который
будет работать еще год.</p><strong>Пробуем на деле</strong>
<p>Поместите в ini-файл строчку вида MaxBuildDate=YYYYMMDD -
например, такую:</p>
<pre class="code">MaxBuildDate=20000101
</pre>
<p>В тестовом режиме система лицензирования считает датой сборки
сегодняшнее число, поэтому важно, чтобы дата, указанная в строке,
уже прошла. Т.е. максимум - вчера. Модифицируйте исходный код
функции <strong>main()</strong>, чтобы он выглядел так:</p>
<pre class="code">int main(int argc, char **argv)
{
char *serial = "Xserialnumber"; // зададим номер непосредственно в коде для простоты
int res = VMProtectSetSerialNumber(serial);
print_state(res);
if (res)
{
VMProtectSerialNumberData sd = {0};
VMProtectGetSerialNumberData(&amp;sd, sizeof(sd));
printf("max. build date: y = %d, m = %d, d = %d\n", sd.dtMaxBuild.wYear, sd.dtMaxBuild.bMonth, sd.dtMaxBuild.bDay);
printf("please register!\n");
return 0;
}
printf("I'm registered\n");
return 0;
}
</pre>
<p>Тогда при запуске программы вы увидите следующее:</p>
<pre class="code">state = SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED
max. build date: y = 2000, m = 1, d = 1
please register!
</pre>
<p>Заменив в ini-файле дату на сегодняшнюю или завтрашнюю, мы
получим "рабочую" программу:</p>
<pre class="code">state = 0
I'm registered
</pre>
<p>Удалите из ini-файла строку MaxBuildDate=..., чтобы она не
мешала нам в дальнейшем.</p><br />
<a href="step18_blacklist.htm">Следующий шаг</a>
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 1.8: Номера из "черного списка"</title>
</head>
<body>
<h1>Шаг 1.8: Номера из "черного списка"</h1>
<p>Номер, помеченный в VMProtect как "заблокированный", больше не
должен приниматься системой лицензирования. При очередной защите
приложения VMProtect запишет в защищаемый файл хеш от номеров
черного списка, вследствие чего система лицензирования в этом приложении откажет при попытке
установить такой номер.</p>
<p>Сократим до минимума код функции <strong>main()</strong>:</p>
<pre class="code">int main(int argc, char **argv)
{
char *serial = "Xserialnumber"; // зададим номер непосредственно в коде для простоты
int res = VMProtectSetSerialNumber(serial);
print_state(res);
return 0;
}
</pre>
<p>Запустим программу и убедимся, что система лицензирования
принимает наш серийный номер:</p>
<pre class="code">state = 0
</pre>
<p>Теперь занесем наш номер в черный список с точки зрения
системы лицензирования. Для этого в ini-файл добавим строку:</p>
<pre class="code">BlackListedSerialNumber=Xserialnumber
</pre>
<p>И снова запускаем программу:</p>
<pre class="code">state = SERIAL_STATE_FLAG_BLACKLISTED
</pre>
<p>Сообщать ли пользователю о занесении его номера в черный список,
или просто сообщить, что номер неверный - оставлено на усмотрение
разработчика. Система лицензирования лишь сообщает программе о
факте использования заблокированного номера.</p><br />
<a href="step19_hwid.htm">Следующий шаг</a>
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,123 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 1.9: Привязка к оборудованию</title>
<style type="text/css">
/*<![CDATA[*/
div.c2 {text-align: center}
p.c1 {color:red;}
/*]]>*/
</style>
</head>
<body>
<h1>Шаг 1.9: Привязка к оборудованию</h1><strong>Получение
идентификатора оборудования</strong>
<p>Прежде чем привязываться к оборудованию, необходимо получить
идентификатор оборудования. Идентификатор помещается в серийный
номер и при передаче этого номера системе лицензирования
происходит проверка соответствия идентификаторов. Поэтому для
начала получим идентификатор нашего оборудования. Сократим
<strong>main()</strong> до самого короткого варианта:</p>
<pre class="code">int main(int argc, char **argv)
{
int nSize = VMProtectGetCurrentHWID(NULL, 0);
char *buf = new char[nSize];
VMProtectGetCurrentHWID(buf, nSize);
printf("HWID: %s\n", buf);
delete [] buf;
return 0;
}
</pre>
<p>Запустив эту программу, мы получим тестовый идентификатор
оборудования, используемый по умолчанию:</p>
<pre class="code">HWID: myhwid
</pre>
<p>Чтобы изменить идентификатор, используемый по умолчанию,
добавьте в ini-файл строку:</p>
<pre class="code">MyHWID=test
</pre>
<p>Запустив программу после этого, мы увидим, что система
лицензирования теперь считает "test" идентификатором
оборудования:</p>
<pre class="code">HWID: test
</pre>
<p class="c1"><strong>Внимание!</strong> реальный идентификатор
оборудования программа будет выдавать только после ее обработки в
VMProtect.</p><br />
<strong>Серийный номер с привязкой к оборудованию</strong>
<p>Чтобы наш тестовый серийный номер был привязан к оборудованию,
добавим в ini-файл еще одну строчку, на этот раз с
идентификатором, "записанным" в номер:</p>
<pre class="code">KeyHWID=test
</pre>
<p>А функцию <strong>main()</strong> слегка усложним, она снова
будет подавать серийный номер и анализировать получаемый
результат:</p>
<pre>
int main(int argc, char **argv)
{
int nSize = VMProtectGetCurrentHWID(NULL, 0);
char *buf = new char[nSize];
VMProtectGetCurrentHWID(buf, nSize);
printf("HWID: %s\n", buf);
delete [] buf;
char *serial = "Xserialnumber";
int res = VMProtectSetSerialNumber(serial);
print_state(res);
return 0;
}
</pre>
<p>Запустив код, получим следующий результат:</p>
<pre class="code">HWID: test
state = 0
</pre>
<p>Система лицензирования сравнила текущий идентификатор
оборудования и тот, который был запиан в серийном номере.
Идентификаторы совпали и функция
<strong>VMProtectSetSerialNumber()</strong> вернула 0 - серийный
номер подходит.</p>
<p>Попробуем теперь "запустить" нашу программу на другом
оборудовании. Для этого поменяем значение "test" параметра MyHWID
в ini-файле на "new test". И снова запустим программу:</p>
<pre class="code">HWID: new test
state = SERIAL_STATE_FLAG_BAD_HWID
</pre>
<p>На этот раз система лицензирования вернула флаг
SERIAL_STATE_FLAG_BAD_HWID, означающий несовпадение реально
идентификатора оборудования с тем, что хранится в серийном
номере. Текущий идентификатор оборудования, выведенный на экран -
"new test", а в серийном номере хранится "test". Поменяв в
ini-файле значение параметра KeyHWID на "new test" можно добиться
работы серийного номера и на этом "оборудовании".</p><br />
<a href="step1A_userdata.htm">Следующий шаг</a>
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,76 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 1.10: Пользовательские данные</title>
</head>
<body>
<h1>Шаг 1.10: Пользовательские данные</h1>
<p>Серийный номер может содержать до 255 байт произвольных
данных, которые система лицензирования без изменений передает
вызывающей программе. Это может быть какая-то дополнительная
информация о продаже, данные, без которых не будет работать
полная версия, или еще что-нибудь. Изменим функцию
<strong>main()</strong>, чтобы она считывала данные из серийного
номера и показывала их на экране:</p>
<pre class="code">int main(int argc, char **argv)
{
char *serial = "Xserialnumber";
int res = VMProtectSetSerialNumber(serial);
print_state(res);
if (res) return 0;
VMProtectSerialNumberData sd = {0};
VMProtectGetSerialNumberData(&amp;sd, sizeof(sd));
printf("Serial number has %d byte(s) of data\n", sd.nUserDataLength);
for (int i = 0; i &lt; sd.nUserDataLength; i++)
printf("%02X ", sd.bUserData[i]);
printf("\n");
return 0;
}
</pre>
<p>Ini-файл при этом сократим до такого вида:</p>
<pre class="code">[TestLicense]
AcceptedSerialNumber=Xserialnumber
</pre>
<p>Теперь запустим программу и убедимся, что наш серийный номер
подходит, но не содержит никаких данных:</p>
<pre class="code">state = 0
Serial number has 0 byte(s) of data
</pre>
<p>Чтобы добавить пользовательские данные в серийный номер,
необходимо создать в ini-файле переменную UserData и присвоить ей
строчку из HEX-символов. Символы должны идти парами, т.е. длина
строки должна быть кратна 2. Строка может быть, например,
такой:</p>
<pre class="code">UserData=010203A0B0C0D0E0
</pre>
<p>В этом случае при запуске программы мы получим следующий
результат:</p>
<pre class="code">state = 0
Serial number has 8 byte(s) of data
01 02 03 A0 B0 C0 D0 E0
</pre><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,109 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 2.1: Создаем новое защищенное приложение</title>
</head>
<body>
<h1>Шаг 2.1: Создаем новое защищенное приложение</h1>
<p>Если на первом этапе мы создавали несколько разных тестовых
приложений для изучения API системы лицензирования, то на втором этапе
приложение будет одно. Оно также будет консольным и в нем будет
функция <strong>foo()</strong>, которая может работать только в
зарегистрированной версии. Вот код нашего тестового
приложения:</p>
<pre class="code">#include &lt;windows.h&gt;
#include &lt;stdio.h&gt;
#include "VMProtectSDK.h"
#define PRINT_HELPER(state, flag) if (state &amp; flag) printf("%s ", #flag)
void print_state(INT state)
{
if (state == 0)
{
printf("state = 0\n");
return;
}
printf("state = ");
PRINT_HELPER(state, SERIAL_STATE_FLAG_CORRUPTED);
PRINT_HELPER(state, SERIAL_STATE_FLAG_INVALID);
PRINT_HELPER(state, SERIAL_STATE_FLAG_BLACKLISTED);
PRINT_HELPER(state, SERIAL_STATE_FLAG_DATE_EXPIRED);
PRINT_HELPER(state, SERIAL_STATE_FLAG_RUNNING_TIME_OVER);
PRINT_HELPER(state, SERIAL_STATE_FLAG_BAD_HWID);
PRINT_HELPER(state, SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED);
printf("\n");
}
char *read_serial(const char *fname)
{
FILE *f;
if (0 != fopen_s(&amp;f, fname, "rb")) return NULL;
fseek(f, 0, SEEK_END);
int s = ftell(f);
fseek(f, 0, SEEK_SET);
char *buf = new char[s + 1];
fread(buf, s, 1, f);
buf[s] = 0;
fclose(f);
return buf;
}
// метод foo() очень короткий, но он нам нужен в виде отдельной функции
// поэтому мы попросим компилятор не делать его inline
__declspec(noinline) void foo()
{
printf("I'm foo!\n");
}
int main(int argc, char **argv)
{
char *serial = read_serial("serial.txt");
int res = VMProtectSetSerialNumber(serial);
delete [] serial;
if (res)
{
printf("serial number is bad\n");
print_state(res);
return 0;
}
printf("serial number is correct, calling foo()\n");
foo();
printf("done\n");
return 0;
}
</pre>
<p>Скомпилируем программу без отладочной информации, но в
настройках линкера попросим создать MAP-файл, который потребуется
для работы VMProtect. При запуске программы мы должны увидеть
следующий текст:</p>
<pre class="code">serial number is bad
state = SERIAL_STATE_FLAG_INVALID
</pre>
<p>В настоящий момент система лицензирования все еще работает в
тестовом режиме, т.к. файл еще не был обработан VMProtect'ом и в
него не был внедрен модуль лицензирования. На <a href=
"step22_vmp.htm">следующем шаге</a> мы создадим проект VMProtect
и попробуем защитить нашу программу.</p><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,42 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 2.2: Создаем проект защиты в VMProtect</title>
<style type="text/css">
</style>
</head>
<body>
<h1>Шаг 2.2: Создаем проект защиты в VMProtect</h1>
<p>Теперь, когда тестовая программа готова, скомпилирована и
рядом с ней находится ее MAP-файл, мы можем запустить VMProtect
Ultimate и открыть исполняемый файл. Нам нужно будет добавить в
проект две функции: _main (так Visual Studio переименовала нашу
функцию main()) и foo(). Обе функции видны в списке функций в
VMProtect в разделе "Функции".</p>
<!-- <p class="c1"><br /><img src="../../images/real_project_functions.png" alt="Дерево проекта" /></p> -->
<p>Далее необходимо инициализировать систему лицензирования.
Перейдите на вкладку "Лицензии" и создайте пару кючей длиной 2048
бит.</p><br />
<a href="step23_product.htm">Следующий шаг</a>
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,70 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 2.3: Первый запуск защищенного продукта</title>
<style type="text/css">
</style>
</head>
<body>
<h1>Шаг 2.3: Первый запуск защищенного продукта</h1>
<p>Система лицензирования инициализирована, так что мы можем
попробовать скомпилировать проект VMPrtoect и запустить
защищенный файл. Запустив его из командной строки мы получим
следующее сообщение:</p>
<pre class="code">C:\test&gt;dummy_app.vmp.exe
serial number is bad
state = SERIAL_STATE_FLAG_INVALID
</pre>
<p>Запустив программу depends.exe, мы можем убедиться, что наш
защищенный файл более не связан с библиотекой VMProtectSDK.dll, а
значит модуль лицензирования встроен в приложение. Список
используемых DLL можно посмотреть и в VMProtect, открыв
защищенный файл и выбрав из раздела "Свойства" секцию "Импорты".</p>
<p><img src="../../images/depends.png" /></p>
<p>Наша защищаемая программа читает серийный номер из файла
serial.txt. Поскольку этого файла сейчас нет, то модулю лицензирования
подается пустой номер, который также не считается корректным.
Перейдем на закладку "лицензии" и сгенерируем серийный номер.
Подробно эта процедура описана <a href=
"../licenses.htm">здесь</a>, мы создадим самый простой серийный
номер без каких-либо ограничений.</p>
<p><img src="../../images/project_add_license.png" /></p>
<p>Затем скопируем серийный номер (в свойствах лицензии выделим поле
"Серийный номер" и нажмем Ctrl+C), создадим рядом с
защищенным приложением файл serial.txt и вставим туда серийный
номер. После запуска программы мы увидим следующее:</p>
<pre class="code">C:\test&gt;dummy_app.vmp.exe
serial number is correct, calling foo()
I'm foo
done
</pre>
<p>Система лицензирования проверила серийный номер и посчитала
его корректным. На <a href="step24_test.htm">следующем шаге</a> мы
попробуем применить некоторые ограничения и посмотрим что из
этого выйдет.</p><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,90 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 2.4: Тестируем результат</title>
</head>
<body>
<h1>Шаг 2.4: Тестируем результат</h1><strong>Срок действия
серийного номера</strong>
<p>Создадим еще один серийный номер с ограничением срока
действия - скажем, 2005-м годом. Эта дата уже прошла и наш номер
должен быть недействительным. Перейдите на закладку "Лицензии" и
нажмите кнопку "Добавить лицензию". В появившемся окне поставьте
галочку "Срок годности" и введите "30 сентября 2005 года".
Создайте номер, скопируйте его и поместите в файл seral.txt,
после чего запустите программу:</p>
<pre class="code">C:\test&gt;dummy_app.vmp.exe
serial number is bad
state = SERIAL_STATE_FLAG_DATE_EXPIRED
</pre>
<p>Модуль лицензирования вернул флаг "срок действия номера
закончен". Вернем рабочий номер обратно в файл serial.txt и
убедимся, что его модуль лицензирования примет без проблем.</p>
<pre class="code">C:\test&gt;dummy_app.vmp.exe
serial number is correct, calling foo()
I'm foo
done
</pre><strong>Занесение номера в черный список</strong>
<p>Предположим, что наш "хороший" серийный номер выложен в
Интернет. Нам необходимо его заблокировать, чтобы в следующих
версиях программы он уже не работал. Для этого мы выбираем его в
списке номеров и нажимаем кнопку "Заблокировать". Сам факт
нажатия кнопки не блокирует серийный номер в защищенном
приложении, однако после повторной защиты файла, он откажется
принимать этот серийный номер. Проверим. Если сейчас запустить
нашу программу, то она примет заблокированный номер без проблем,
т.к. это старая версия программы и она еще не знает о
блокировке:</p>
<pre class="code">C:\test&gt;dummy_app.vmp.exe
serial number is correct, calling foo()
I'm foo
done
</pre>
<p>Сделаем копию нашей программы и назовем ее
"dummy_app1.vmp.exe", а после этого перейдем в VMProtect и
повторно защитим наше приложение, после чего запустим новую
версию программы:</p>
<pre class="code">C:\test&gt;dummy_app.vmp.exe
serial number is bad
state = SERIAL_STATE_FLAG_BLACKLISTED
</pre>
<p>Теперь для сравнения еще раз запустим старую версию
программы:</p>
<pre class="code">C:\test&gt;dummy_app1.vmp.exe
serial number is correct, calling foo()
I'm foo
done
</pre>
<p>Старая версия ничего не знает о блокировании номера и
продолжает работать как и раньше. </p><br />
<br /><p>На <a href=
"step25_codelock.htm">последнем шаге</a> мы попробуем привязать
выполняемый код к серийному номеру. Перед этим разблокируйте
серийный номер и перезащитите приложение в VMProtect, чтобы оно
снова принимало наш серийный номер. Или создайте новую
лицензию.</p><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,144 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Шаг 2.5. Привязка кода к серийному номеру</title>
<style type="text/css">
/*<![CDATA[*/
p.c2 {color:red;}
span.c1 {background-color:yellow;}
/*]]>*/
</style>
</head>
<body>
<h1>Шаг 2.5. Привязка кода к серийному номеру</h1>
<p>Одним из наиболее популярных способов взлома программ является
поиск проверки серийного номера и последующего условного
перехода. Если номер корректен, то ход выполнения программы идет
по одной ветке, если некорректен, то по другой. Хакер находит
этот переход и заменяет его на безусловный переход на
"правильную" ветку. Давайте "взломаем" таким образом нашу
тестовую программу. На уровне исходников, конечно же. "Отключим"
условный переход:</p>
<pre class="code">char *serial = read_serial("serial.txt");
int res = VMProtectSetSerialNumber(serial);
delete [] serial;
if (<span class="c1">false &amp;&amp;</span> res)
{
</pre>
<p>Теперь наша программа примет любой серийный номер и будет
работать как ни в чем не бывало. Безусловно, если файл защищен
VMProtect, то даже опытному хакеру потребуется не один месяц,
чтобы найти и исправить этот переход так, как сделали это мы. А с
учетом того, что правильно защищенная программа проверяет
серийный номер не в одном месте и не всегда, то даже такая
простая проверка уже достаточно надежна. Однако мы пойдем
дальше.</p><strong>Привяжем код к серийному номеру</strong>
<p class="c2"><strong>Внимание!</strong> демо-версия VMProtect
имеет ограничение на количество обрабатываемых функций:
обрабатывается только одна функция. Поэтому в случае
использования демо-версии, необходимо включать в проект только
функцию foo(), т.к. в противном случае демо-версия VMProtect
может выбрать для защиты функцию main() и привязка кода к
серийному номеру не сработает.</p>
<p>Система лицензирования VMProtect позволяет привязать код одной
или нескольких функций к серийному номеру так, что они не будут
работать без корректного номера. Тело функции виртуализируется,
потом шифруется и может быть расшифровано только при наличии
корректного серийного номера. То есть даже если хакер найдет и
исправит условный переход в коде проверки номера, функции,
привязанные к номеру, все равно не будут работать. Давайте
попробуем. В VMProtect в разделе "Функции" выберем функцию <strong>foo()</strong> и в
правой панели изменим значение опции "Привязать к серийному номеру" на "Да".</p>
<p><img src="../../images/lock_to_serial.png" /></p>
<p>После этого защитим наше приложение. С учетом
того, что оно "взломано", поместим в файл serial.txt произвольный
текст и запустим приложение. В консоли появится текст:</p>
<pre class="code">C:\test&gt;dummy_app.vmp.exe
serial number is correct, calling foo()
</pre>
<p>То есть хакер "исправил" нужный условный переход и программа
пошла по "правильной" ветке. Однако в момент вызова
<strong>foo()</strong> программа выводит сообщение:</p>
<p><img src="../../images/codelock_error.png" /></p>
<p>Так как мы привязали функцию <strong>foo()</strong> к
серийному номеру, а у хакера его нет, то при попытке расшифровать
код функции модуль лицензирования выдал сообщение о невозможности
продолжить выполнение программы. После нажатия кнопки "ОК"
программа завершится и в консоли мы не увидим строчки
"done".</p><strong>Что привязывать к серийному номеру?</strong>
<p>Привязывать к серийному номеру имеет смысл те функции, которые
вызываются только в зарегистрированной версии программы. Так как
привязка возможна только при использовании виртуализации, то
необходимо принимать во внимание возможное падение
производительности. Скажем, если текстовый редактор не позволяет
сохранять результаты своей работы в демо-версии, то к серийному
номеру можно привязать функцию сохранения документа. Если эта
функция вызывает ряд других в процессе работы, то их привязывать
уже не обязательно, так как без основной функции от них будет
немного толку.</p>
<p>Также необходимо помнить, что вызов привязанной функции без
серийного номера приведет к завершению работы программы без
возможности сохранения результатов работы, поэтому тщательно
тестируйте защищаемую программу, чтобы она не позволяла вызвать
такие функции в демо-режиме. В примере с текстовым редактором
убедитесь, что в демо-режиме пункт меню "Сохранить" всегда
неактивен, что комбинация Ctrl+S не срабатывает и что при
закрытии программы также не предлагается сохранить изменения. В
противном случае пользователь может составить негативное мнение о
вашей программе.</p><strong>Привязка к серийному номеру и
нерабочие номера</strong>
<p>При вызове функции <strong>VMProtectSetSerialNumber()</strong>
модуль лицензирования проверяет переданный серийный номер и
зашифрованные участки кода будут выполняться только в том случае,
если на момент проверки серийный номер был полностью корректным -
не занесенным в черный список, с правильным идентификатором
оборудования, с неистекшим сроком годности и т.п. В этом случае все
зашифрованные процедуры будут выполняться до завершения работы
приложения или до нового вызова
<strong>VMProtectSetSerialNumber()</strong>.</p>
<p>Некоторые ограничения могут "сработать" в процессе выполнения
программы: например, может истечь время работы программы или
окончится срок действия серийного номера. В этом случае модуль
лицензирования продолжит расшифровывать и выполнять функции,
привязанные к серийному номеру. Это делается потому, что
защищенному приложению будет сложно отследить момент срабатывания
ограничений и соответствующим образом изменить модель своего
поведения (заблокировать пункты меню и т.п). Если модуль
лицензирования неожиданно для приложения перестанет выполнять
привязанные к серийному номеру участки кода, это с большой
вероятностью приведет к неработоспособности приложения. Поэтому
все решается в момент установки серийного номера и именно в этот
момент определяется режим, в котором будет работать
приложение.</p><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>