Добрый день.
Я использую vmprotect для защиты Windows версии своего продукта. Linux версия готовится к выпуску и я хотел бы использовать те же лицезионные ключи что и на Windows.
Мне требуется только базовый функционал - декодировать информацию из ключа (имя пользователя, max build date, etc.), защита не нужна.
Есть ли пример-исходник как сделать декодирование информации из ключа? Еще лучше - уже портированный для Linux.
Декодирование ключа на Linux
Re: Декодирование ключа на Linux
А в чем у вас возникла сложность? Генерация серийника полностью есть в исходных кодах (\Keygen\DLL\Sources\), на основе этого кода декрипт серийника пишется без проблем в том числе и для Linux.
Re: Декодирование ключа на Linux
Проблем нет, разбираться в исходниках генерации ключа, потом самому писать декодирование, ловить баги и т.д. - непродуктивно.
Именно поэтому люди собственно и платят деньги за готовые решения (особенно выбирают Ultimate версии) - сэкономить себе время.
Т.к. алгоритм декодирования ключа не составляет секрета (его можно восстановить по кодированию, как вы говорите), то расшарьте его код, по крайней мере для клиентов. Номер моего ордера: 523814, мой мейл вам известен, copy-paste труда не составит.
Тем более что он уже есть в недрах VMProtect - это сэкономит тучу моего времени и добавит шансов на продление лицензии, в том числе и тем клиентам, которых я привел к вам.
Именно поэтому люди собственно и платят деньги за готовые решения (особенно выбирают Ultimate версии) - сэкономить себе время.
Т.к. алгоритм декодирования ключа не составляет секрета (его можно восстановить по кодированию, как вы говорите), то расшарьте его код, по крайней мере для клиентов. Номер моего ордера: 523814, мой мейл вам известен, copy-paste труда не составит.
Тем более что он уже есть в недрах VMProtect - это сэкономит тучу моего времени и добавит шансов на продление лицензии, в том числе и тем клиентам, которых я привел к вам.
Re: Декодирование ключа на Linux
Дело в том, что в нашем рантайме используется переделанная RSA-ная библиотека, работающая с открытым ключем через криптоконтейнеры, поэтому наш кусок кода все равно придется переделывать под библиотеку из кейгена. Я постараюсь в ближайшее время написать разбор ключа на библиотеке из кейгена.
Re: Декодирование ключа на Linux
Буду очень благодарен. Пока откладываю эту задачу до вашего ответа.
Re: Декодирование ключа на Linux
Ну вот как-то так:
в stdafx.h добавить:
все запчасти можно взять из %VMProtect%\Keygen\DLL\Sources\
Code: Select all
// DecodeSerial.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
std::vector<byte> Base64ToVector(const char *p)
{
if (!p || !p[0]) return std::vector<byte>(); // empty vector for empty string
size_t nSrcLen = strlen(p);
std::vector<byte> res;
base64_decode(p, nSrcLen, res);
return res;
}
std::wstring FromUTF8(const char *src, size_t len)
{
int nLength = static_cast<int>(len);
int nSize = MultiByteToWideChar(CP_UTF8, 0, src, nLength, NULL, 0);
std::wstring dest;
dest.resize(nSize);
int nSize2 = MultiByteToWideChar(CP_UTF8, 0, src, nLength, (LPWSTR)dest.c_str(), nSize);
return dest;
}
size_t g_nBits = 2048;
const char *g_vModulus = "rnK4CvdHf4d3DTtS7B7Fyu5kzT16BTWlecKTZcjw5Ji9BTLfhjgIxSyY6uqD2wNxd+qTzNY4PHvAf8lwxsLE9ir7sDhrDgzLp5PR5EW5nuZgHC+QKpXoaXH9Q73i6KcfDOUSHquQmRNtDHqyublT9/yv1pLuA+mCC+/gWZhgdAGZbwA0Ek61mGH1YFOUY+qLGyiJwGSMBXDWgEAm36wUHyTjZhN2003JuJwtpT8IWKiR5sy+vNQdtj+QEeyADbTFuYv5RHXUkUVvc0RUXecFLAQuE/1i1AJDAd5s4oDKUizZ10nCsHawSnHn4pgdQFzvhxnNTEVcjhcWMW0+/Zvfhw==";
const char *g_vPrivate = "qA/5YwcsKJ63gVXf438aCxF0p45Mmew/CXj9TBg0i+biY7nJQqOFP4BhqiBY+4zrqh2iWrse3pZStEm7jqFh488xP2p7KMQHB+EPWx4ZYA6OFVl1SLG3gK7C0pqDmqQ289NUi5u56N+gNV+YA/mZ/dXBCbXv/HDgSuPEfkygz+CG20uRWoKbF+JKF6dHLbQHnn7l9nu1ht7+6NeL32UV8sEu8E508qF4cEni4RPu4cvnp98t8FF5e10JFpCE5wjkg47GQ+vUB5z+Z2AzuQdW8EHPvWwn+TNvcIh2tHEPWT39IeZ2X2KbfLCqdW4T2wwHHesiNwhqOwpNnxzHmDyaAQ==";
const char *g_vPublic = "AAEAAQ==";
enum eChunks
{
SERIAL_CHUNK_VERSION = 0x01, // 1 byte of data - version
SERIAL_CHUNK_USER_NAME = 0x02, // 1 + N bytes - length + N bytes of customer's name (without enging \0).
SERIAL_CHUNK_EMAIL = 0x03, // 1 + N bytes - length + N bytes of customer's email (without ending \0).
SERIAL_CHUNK_HWID = 0x04, // 1 + N bytes - length + N bytes of hardware id (N % 4 == 0)
SERIAL_CHUNK_EXP_DATE = 0x05, // 4 bytes - (year << 16) + (month << 8) + (day)
SERIAL_CHUNK_RUNNING_TIME_LIMIT = 0x06, // 1 byte - number of minutes
SERIAL_CHUNK_PRODUCT_CODE = 0x07, // 8 bytes - used for decrypting some parts of exe-file
SERIAL_CHUNK_USER_DATA = 0x08, // 1 + N bytes - length + N bytes of user data
SERIAL_CHUNK_MAX_BUILD = 0x09, // 4 bytes - (year << 16) + (month << 8) + (day)
SERIAL_CHUNK_END = 0xFF // 4 bytes - checksum: the first four bytes of sha-1 hash from the data before that chunk
};
#pragma pack(push, 1)
typedef struct
{
WORD wYear;
BYTE bMonth;
BYTE bDay;
} VMProtectDate;
typedef struct
{
INT nState; // VMProtectSerialStateFlags
wchar_t wUserName[256]; // user name
wchar_t wEMail[256]; // email
VMProtectDate dtExpire; // date of serial number expiration
VMProtectDate dtMaxBuild; // max date of build, that will accept this key
INT bRunningTime; // running time in minutes
BYTE nUserDataLength; // length of user data in bUserData
BYTE bUserData[255]; // up to 255 bytes of user data
} VMProtectSerialNumberData;
bool DecodeSerial(const char *serial, VMProtectSerialNumberData *data)
{
std::vector<byte> sn = Base64ToVector(serial);
if (sn.size() < 16)
return false;
std::vector<byte> modulus = Base64ToVector(g_vModulus);
std::vector<byte> exp = Base64ToVector(g_vPublic);
Bignum e = bignum_from_bytes(&exp[0], exp.size());
Bignum n = bignum_from_bytes(&modulus[0], modulus.size());
Bignum x = bignum_from_bytes(&sn[0], sn.size());
// the second check of data length, data is too long to crypt
if (bignum_cmp(n, x) < 0)
return false;
Bignum y = modpow(x, e, n);
int nBytes;
byte *pRes = bignum_to_bytes(y, &nBytes);
sn.clear();
sn.insert(sn.end(), pRes, pRes + nBytes);
delete [] pRes;
if (sn[0] != 0 && sn[1] != 2)
return false;
// skip padding
size_t pos = 2;
for (pos = 2; pos < sn.size(); pos++) {
if (sn[pos] == 0) {
pos++;
break;
}
}
if (pos == sn.size())
return false;
size_t start = pos;
while (pos < sn.size()) {
byte b = sn[pos];
byte sz;
std::wstring str;
pos++;
switch (b) {
case SERIAL_CHUNK_VERSION:
if (sn[pos] != 1)
return false;
pos += 1;
break;
case SERIAL_CHUNK_EXP_DATE:
memcpy(&data->dtExpire, &sn[pos], sizeof(data->dtExpire));
pos += 4;
break;
case SERIAL_CHUNK_RUNNING_TIME_LIMIT:
data->bRunningTime = sn[pos];
pos += 1;
break;
case SERIAL_CHUNK_PRODUCT_CODE:
pos += 8;
break;
case SERIAL_CHUNK_MAX_BUILD:
memcpy(&data->dtMaxBuild, &sn[pos], sizeof(data->dtMaxBuild));
pos += 4;
break;
case SERIAL_CHUNK_USER_NAME:
sz = sn[pos++];
str = FromUTF8(reinterpret_cast<const char *>(&sn[pos]), sz);
memcpy(&data->wUserName, &str[0], str.size() * sizeof(wchar_t));
pos += sz;
break;
case SERIAL_CHUNK_EMAIL:
sz = sn[pos++];
str = FromUTF8(reinterpret_cast<const char *>(&sn[pos]), sz);
memcpy(&data->wEMail, &str[0], str.size() * sizeof(wchar_t));
pos += sz;
break;
case SERIAL_CHUNK_HWID:
sz = sn[pos++];
// read HWID
pos += sz;
break;
case SERIAL_CHUNK_USER_DATA:
sz = sn[pos++];
data->nUserDataLength = sz;
memcpy(&data->bUserData, &sn[pos], sz);
pos += sz;
break;
case SERIAL_CHUNK_END:
if (sn.size() - pos < 3)
return false;
// compute hash
SHA1Context ctx;
SHA1Reset(&ctx);
SHA1Input(&ctx, &sn[start], pos - start - 1);
SHA1Result(&ctx);
// check CRC
const byte *p = (const byte *)&ctx.Message_Digest;
for (size_t i = 0; i < 4; i++) {
if (sn[pos + i] != p[i])
return false;
}
pos = sn.size();
break;
}
}
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
VMProtectSerialNumberData data = {0};
DecodeSerial("IOtjdo0yTQFhExs0hoDu7Y6O3jQgsJqSu2eytTmlsFI1+XJdPXdhRJmSkqzld/RSGes7wqxmxtFQUakrHxkAruXPgOPRZX1Mr/d717LlpDW1DvJJ7ndD/fAziYcKGiQ1HfWjwXWAzjM/A1zT0X333E8zCYmGrWHPC0u94UqjabJ2EF4Wu5K+6zZX8Gy+msV8BarrW1VdGCcEIMA/wVD5t1nrhU4PMAsqzZHkmXuH9RT8AWCBz2n1RWqnk3YOCNFJ8Oywi7YBjVnyzTTHTOojBXo77xmMFoncxUoUzFA6P5653KK14nZ2A4yXb4t2Ia5XOFMcfEQ4HOfLK9dnD2BeGA==", &data);
return 0;
}
Code: Select all
#include <windows.h>
#include <vector>
#ifndef byte
typedef unsigned char byte;
#endif
#include "b64.h"
#include "sha-1.h"
#include "sshbn.h"
Re: Декодирование ключа на Linux
Большое спасибо!
В течении пары дней посмотрю-поразбираюсь, задам вопросы если возникнут.
В течении пары дней посмотрю-поразбираюсь, задам вопросы если возникнут.
Re: Декодирование ключа на Linux
Доброго дня.
Все моменты понятны, кроме одно - где взять мой публичный ключ?
VMProtect экспортирует только g_vPrivate, g_vModulus и g_vProductCode.
Имеется ввиду что g_vProductCode и есть публичный ключ?
Все моменты понятны, кроме одно - где взять мой публичный ключ?
VMProtect экспортирует только g_vPrivate, g_vModulus и g_vProductCode.
Имеется ввиду что g_vProductCode и есть публичный ключ?
Re: Декодирование ключа на Linux
Публичный ключ можно взять из VMP файла. Для кейгена он не экспортируется.