mirror of
https://github.com/Obfuscator-Collections/VMProtect.git
synced 2024-12-26 08:20:19 +03:00
5ec92ee05e
Version 3.x.x
1135 lines
36 KiB
C++
1135 lines
36 KiB
C++
#include "common.h"
|
|
#include "objects.h"
|
|
#include "utils.h"
|
|
#include "core.h"
|
|
#include "crypto.h"
|
|
#include "licensing_manager.h"
|
|
#include "hwid.h"
|
|
#include "loader.h"
|
|
|
|
#if defined(__unix__)
|
|
#include <sys/time.h>
|
|
#include <curl/curl.h>
|
|
#endif
|
|
|
|
/**
|
|
* exported functions
|
|
*/
|
|
|
|
#ifdef VMP_GNU
|
|
EXPORT_API int WINAPI ExportedSetSerialNumber(const char *serial) __asm__ ("ExportedSetSerialNumber");
|
|
EXPORT_API int WINAPI ExportedGetSerialNumberState() __asm__ ("ExportedGetSerialNumberState");
|
|
EXPORT_API bool WINAPI ExportedGetSerialNumberData(VMProtectSerialNumberData *data, int size) __asm__ ("ExportedGetSerialNumberData");
|
|
EXPORT_API int WINAPI ExportedActivateLicense(const char *code, char *serial, int size) __asm__ ("ExportedActivateLicense");
|
|
EXPORT_API int WINAPI ExportedDeactivateLicense(const char *serial) __asm__ ("ExportedDeactivateLicense");
|
|
EXPORT_API int WINAPI ExportedGetOfflineActivationString(const char *code, char *buf, int size) __asm__ ("ExportedGetOfflineActivationString");
|
|
EXPORT_API int WINAPI ExportedGetOfflineDeactivationString(const char *serial, char *buf, int size) __asm__ ("ExportedGetOfflineDeactivationString");
|
|
EXPORT_API void WINAPI ExportedDecryptBuffer(uint8_t *buffer) __asm__ ("ExportedDecryptBuffer");
|
|
#elif defined(USE_WININET)
|
|
#include <wininet.h>
|
|
#else
|
|
#ifndef WIN_DRIVER
|
|
#include <winhttp.h>
|
|
#include <xstring>
|
|
#endif
|
|
#endif
|
|
|
|
int WINAPI ExportedSetSerialNumber(const char *serial)
|
|
{
|
|
LicensingManager *licensing_manager = Core::Instance()->licensing_manager();
|
|
return licensing_manager ? licensing_manager->SetSerialNumber(serial) : SERIAL_STATE_FLAG_CORRUPTED;
|
|
}
|
|
|
|
int WINAPI ExportedGetSerialNumberState()
|
|
{
|
|
LicensingManager *licensing_manager = Core::Instance()->licensing_manager();
|
|
return licensing_manager ? licensing_manager->GetSerialNumberState() : SERIAL_STATE_FLAG_CORRUPTED;
|
|
}
|
|
|
|
bool WINAPI ExportedGetSerialNumberData(VMProtectSerialNumberData *data, int size)
|
|
{
|
|
LicensingManager *licensing_manager = Core::Instance()->licensing_manager();
|
|
return licensing_manager ? licensing_manager->GetSerialNumberData(data, size) : false;
|
|
}
|
|
|
|
int WINAPI ExportedActivateLicense(const char *code, char *serial, int size)
|
|
{
|
|
LicensingManager *licensing_manager = Core::Instance()->licensing_manager();
|
|
return licensing_manager ? licensing_manager->ActivateLicense(code, serial, size) : ACTIVATION_NOT_AVAILABLE;
|
|
}
|
|
|
|
int WINAPI ExportedDeactivateLicense(const char *serial)
|
|
{
|
|
LicensingManager *licensing_manager = Core::Instance()->licensing_manager();
|
|
return licensing_manager ? licensing_manager->DeactivateLicense(serial) : ACTIVATION_NOT_AVAILABLE;
|
|
}
|
|
|
|
int WINAPI ExportedGetOfflineActivationString(const char *code, char *buf, int size)
|
|
{
|
|
LicensingManager *licensing_manager = Core::Instance()->licensing_manager();
|
|
return licensing_manager ? licensing_manager->GetOfflineActivationString(code, buf, size) : ACTIVATION_NOT_AVAILABLE;
|
|
}
|
|
|
|
int WINAPI ExportedGetOfflineDeactivationString(const char *serial, char *buf, int size)
|
|
{
|
|
LicensingManager *licensing_manager = Core::Instance()->licensing_manager();
|
|
return licensing_manager ? licensing_manager->GetOfflineDeactivationString(serial, buf, size) : ACTIVATION_NOT_AVAILABLE;
|
|
}
|
|
|
|
void WINAPI ExportedDecryptBuffer(uint8_t *buffer)
|
|
{
|
|
LicensingManager *licensing_manager = Core::Instance()->licensing_manager();
|
|
if (licensing_manager)
|
|
licensing_manager->DecryptBuffer(buffer);
|
|
}
|
|
|
|
/**
|
|
* LicensingManager
|
|
*/
|
|
|
|
#ifdef __APPLE__
|
|
|
|
#include "CFGregorianDateCreate.hpp"
|
|
|
|
uint32_t GetTickCount()
|
|
{
|
|
const int64_t one_million = 1000 * 1000;
|
|
mach_timebase_info_data_t timebase_info;
|
|
mach_timebase_info(&timebase_info);
|
|
|
|
// mach_absolute_time() returns billionth of seconds,
|
|
// so divide by one million to get milliseconds
|
|
return static_cast<uint32_t>((mach_absolute_time() * timebase_info.numer) / (one_million * timebase_info.denom));
|
|
}
|
|
#elif defined(WIN_DRIVER)
|
|
uint32_t GetTickCount()
|
|
{
|
|
LARGE_INTEGER tick_count;
|
|
KeQueryTickCount(&tick_count);
|
|
return static_cast<uint32_t>(tick_count.QuadPart * KeQueryTimeIncrement() / 10000);
|
|
}
|
|
#endif
|
|
#ifdef __unix__
|
|
unsigned long GetTickCount()
|
|
{
|
|
struct timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
|
}
|
|
#endif
|
|
LicensingManager::LicensingManager(uint8_t *data, uint32_t size, uint8_t *key)
|
|
: start_(0), serial_(NULL)
|
|
{
|
|
CriticalSection::Init(critical_section_);
|
|
session_key_ = 0 - static_cast<uint32_t>(loader_data->session_key());
|
|
license_data_ = new CryptoContainer(data, size, key);
|
|
start_tick_count_ = GetTickCount();
|
|
save_state(SERIAL_STATE_FLAG_INVALID);
|
|
}
|
|
|
|
LicensingManager::~LicensingManager()
|
|
{
|
|
delete license_data_;
|
|
delete serial_;
|
|
CriticalSection::Free(critical_section_);
|
|
}
|
|
|
|
int LicensingManager::save_state(int new_state)
|
|
{
|
|
if (new_state & (SERIAL_STATE_FLAG_CORRUPTED | SERIAL_STATE_FLAG_INVALID | SERIAL_STATE_FLAG_BLACKLISTED | SERIAL_STATE_FLAG_BAD_HWID)) {
|
|
product_code_ = 0;
|
|
if (serial_) {
|
|
delete serial_;
|
|
serial_ = NULL;
|
|
}
|
|
} else if (new_state & (SERIAL_STATE_FLAG_DATE_EXPIRED | SERIAL_STATE_FLAG_RUNNING_TIME_OVER | SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED)) {
|
|
if (state_ == SERIAL_STATE_FLAG_INVALID)
|
|
product_code_ = 0;
|
|
}
|
|
state_ = new_state;
|
|
return state_;
|
|
}
|
|
|
|
bool LicensingManager::CheckLicenseDataCRC() const
|
|
{
|
|
size_t crc_pos = license_data_->GetDWord(FIELD_CRC_OFFSET * sizeof(uint32_t));
|
|
size_t size = crc_pos + 16;
|
|
if (size != license_data_->size())
|
|
return false; // bad key size
|
|
|
|
// CRC check
|
|
SHA1 hash;
|
|
hash.Input(license_data_->data(), crc_pos);
|
|
const uint8_t *p = hash.Result();
|
|
for (size_t i = crc_pos; i < size; i++) {
|
|
if (license_data_->GetByte(i) != p[i - crc_pos])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int LicensingManager::SetSerialNumber(const char *serial)
|
|
{
|
|
CriticalSection cs(critical_section_);
|
|
|
|
save_state(SERIAL_STATE_FLAG_INVALID);
|
|
|
|
if (!serial)
|
|
return SERIAL_STATE_FLAG_INVALID; // the key is empty
|
|
|
|
size_t len = 0;
|
|
while (serial[len]) {
|
|
len++;
|
|
}
|
|
if (!len)
|
|
return SERIAL_STATE_FLAG_INVALID; // the key is empty
|
|
|
|
// decode serial number from base64
|
|
uint8_t *binary_serial = new uint8_t[len];
|
|
if (!Base64Decode(serial, len, binary_serial, len) || len < 16) {
|
|
delete [] binary_serial;
|
|
return SERIAL_STATE_FLAG_INVALID;
|
|
}
|
|
|
|
// check license data integrity
|
|
if (!CheckLicenseDataCRC()) {
|
|
delete [] binary_serial;
|
|
return save_state(SERIAL_STATE_FLAG_CORRUPTED);
|
|
}
|
|
|
|
// check serial by black list
|
|
size_t black_list_size = license_data_->GetDWord(FIELD_BLACKLIST_SIZE * sizeof(uint32_t));
|
|
if (black_list_size) {
|
|
size_t black_list_offset = license_data_->GetDWord(FIELD_BLACKLIST_OFFSET * sizeof(uint32_t));
|
|
|
|
SHA1 hash;
|
|
hash.Input(binary_serial, len);
|
|
const uint32_t *p = reinterpret_cast<const uint32_t *>(hash.Result());
|
|
int min = 0;
|
|
int max = (int)black_list_size / 20 - 1;
|
|
while (min <= max) {
|
|
int i = (min + max) / 2;
|
|
bool blocked = true;
|
|
for (size_t j = 0; j < 20 / sizeof(uint32_t); j++) {
|
|
uint32_t dw = license_data_->GetDWord(black_list_offset + i * 20 + j * sizeof(uint32_t));
|
|
if (dw == p[j])
|
|
continue;
|
|
|
|
if (__builtin_bswap32(dw) > __builtin_bswap32(p[j])) {
|
|
max = i - 1;
|
|
} else {
|
|
min = i + 1;
|
|
}
|
|
blocked = false;
|
|
break;
|
|
}
|
|
if (blocked) {
|
|
delete[] binary_serial;
|
|
return save_state(SERIAL_STATE_FLAG_BLACKLISTED);
|
|
}
|
|
}
|
|
}
|
|
|
|
// decode serial number
|
|
BigNumber x(binary_serial, len);
|
|
delete [] binary_serial;
|
|
|
|
serial_ = x.modpow(*license_data_,
|
|
license_data_->GetDWord(FIELD_PUBLIC_EXP_OFFSET * sizeof(uint32_t)), license_data_->GetDWord(FIELD_PUBLIC_EXP_SIZE * sizeof(uint32_t)),
|
|
license_data_->GetDWord(FIELD_MODULUS_OFFSET * sizeof(uint32_t)), license_data_->GetDWord(FIELD_MODULUS_SIZE * sizeof(uint32_t)));
|
|
|
|
if (!serial_)
|
|
return SERIAL_STATE_FLAG_INVALID;
|
|
|
|
if (serial_->GetByte(0) != 0 || serial_->GetByte(1) != 2)
|
|
return SERIAL_STATE_FLAG_INVALID;
|
|
|
|
size_t pos;
|
|
for (pos = 2; pos < serial_->size(); pos++) {
|
|
if (!serial_->GetByte(pos)) {
|
|
pos++;
|
|
break;
|
|
}
|
|
}
|
|
if (pos == serial_->size())
|
|
return SERIAL_STATE_FLAG_INVALID;
|
|
|
|
start_ = pos;
|
|
return ParseSerial(NULL);
|
|
}
|
|
|
|
uint32_t LicensingManager::GetCurrentDate()
|
|
{
|
|
uint32_t cur_date;
|
|
#ifdef VMP_GNU
|
|
time_t rawtime;
|
|
time(&rawtime);
|
|
struct tm local_tm;
|
|
tm *timeinfo = localtime_r(&rawtime, &local_tm);
|
|
cur_date = ((timeinfo->tm_year + 1900) << 16) + (static_cast<uint8_t>(timeinfo->tm_mon + 1) << 8) + static_cast<uint8_t>(timeinfo->tm_mday);
|
|
#elif defined(WIN_DRIVER)
|
|
LARGE_INTEGER sys_time;
|
|
LARGE_INTEGER local_time;
|
|
TIME_FIELDS time_fields;
|
|
|
|
KeQuerySystemTime(&sys_time);
|
|
ExSystemTimeToLocalTime(&sys_time, &local_time);
|
|
RtlTimeToTimeFields(&local_time, &time_fields);
|
|
cur_date = (time_fields.Year << 16) + (static_cast<uint8_t>(time_fields.Month) << 8) + static_cast<uint8_t>(time_fields.Day);
|
|
#else
|
|
typedef struct _KSYSTEM_TIME
|
|
{
|
|
ULONG LowPart;
|
|
LONG High1Time;
|
|
LONG High2Time;
|
|
} KSYSTEM_TIME, *PKSYSTEM_TIME;
|
|
|
|
typedef struct _KUSER_SHARED_DATA
|
|
{
|
|
ULONG TickCountLowDeprecated;
|
|
ULONG TickCountMultiplier;
|
|
KSYSTEM_TIME InterruptTime;
|
|
KSYSTEM_TIME SystemTime;
|
|
KSYSTEM_TIME TimeZoneBias;
|
|
//...
|
|
} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;
|
|
|
|
PKUSER_SHARED_DATA user_shared_data = reinterpret_cast<PKUSER_SHARED_DATA>(0x7FFE0000);
|
|
LARGE_INTEGER sys_time, time_zone_bias, local_time;
|
|
while (true) {
|
|
sys_time.HighPart = user_shared_data->SystemTime.High1Time;
|
|
sys_time.LowPart = user_shared_data->SystemTime.LowPart;
|
|
if (sys_time.HighPart == user_shared_data->SystemTime.High2Time)
|
|
break;
|
|
}
|
|
while (true) {
|
|
time_zone_bias.HighPart = user_shared_data->TimeZoneBias.High1Time;
|
|
time_zone_bias.LowPart = user_shared_data->TimeZoneBias.LowPart;
|
|
if (time_zone_bias.HighPart == user_shared_data->TimeZoneBias.High2Time)
|
|
break;
|
|
}
|
|
local_time.QuadPart = sys_time.QuadPart - time_zone_bias.QuadPart;
|
|
|
|
__int64 total_days_since_1601 = local_time.QuadPart / 864000000000ull;
|
|
uint32_t number_of_400s = static_cast<uint32_t>(total_days_since_1601 / 146097);
|
|
total_days_since_1601 -= number_of_400s * 146097;
|
|
uint32_t number_of_100s = static_cast<uint32_t>((total_days_since_1601 * 100 + 75) / 3652425);
|
|
total_days_since_1601 -= number_of_100s * 36524;
|
|
uint32_t number_of_4s = static_cast<uint32_t>(total_days_since_1601 / 1461);
|
|
total_days_since_1601 -= number_of_4s * 1461;
|
|
uint16_t year = static_cast<uint16_t>((total_days_since_1601 * 100 + 75) / 36525);
|
|
total_days_since_1601 -= 365 * year;
|
|
year = static_cast<uint16_t>((number_of_400s * 400) + (number_of_100s * 100) + (number_of_4s * 4) + year + 1601);
|
|
uint16_t day = static_cast<uint16_t>(total_days_since_1601 + 1);
|
|
int days_in_month[] = {31, ((year % 400 == 0) || (year % 100 != 0) && (year % 4 == 0)) ? 29 : 28,
|
|
31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
|
};
|
|
uint8_t month = 1;
|
|
for (size_t i = 0; i < _countof(days_in_month); i++) {
|
|
if (day > days_in_month[i]) {
|
|
++month;
|
|
day -= days_in_month[i];
|
|
} else
|
|
break;
|
|
}
|
|
assert(month <= 12);
|
|
cur_date = (year << 16) + (static_cast<uint8_t>(month) << 8) + static_cast<uint8_t>(day);
|
|
#endif
|
|
|
|
return std::max(cur_date, loader_data->server_date());
|
|
}
|
|
|
|
int LicensingManager::ParseSerial(VMProtectSerialNumberData *data)
|
|
{
|
|
if (!serial_)
|
|
return SERIAL_STATE_FLAG_INVALID;
|
|
|
|
int new_state = state_ & (SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED | SERIAL_STATE_FLAG_DATE_EXPIRED | SERIAL_STATE_FLAG_RUNNING_TIME_OVER);
|
|
size_t pos = start_;
|
|
while (pos < serial_->size()) {
|
|
uint8_t b = serial_->GetByte(pos++);
|
|
uint8_t s;
|
|
switch (b) {
|
|
case SERIAL_CHUNK_VERSION:
|
|
if (serial_->GetByte(pos) != 1)
|
|
return save_state(SERIAL_STATE_FLAG_INVALID);
|
|
pos += 1;
|
|
break;
|
|
case SERIAL_CHUNK_EXP_DATE:
|
|
uint32_t exp_date;
|
|
exp_date = serial_->GetDWord(pos);
|
|
if ((new_state & SERIAL_STATE_FLAG_DATE_EXPIRED) == 0) {
|
|
if (license_data_->GetDWord(FIELD_BUILD_DATE * sizeof(uint32_t)) > exp_date || GetCurrentDate() > exp_date)
|
|
new_state |= SERIAL_STATE_FLAG_DATE_EXPIRED;
|
|
}
|
|
if (data) {
|
|
data->dtExpire.wYear = exp_date >> 16;
|
|
data->dtExpire.bMonth = static_cast<uint8_t>(exp_date >> 8);
|
|
data->dtExpire.bDay = static_cast<uint8_t>(exp_date);
|
|
}
|
|
pos += 4;
|
|
break;
|
|
case SERIAL_CHUNK_RUNNING_TIME_LIMIT:
|
|
s = serial_->GetByte(pos);
|
|
if ((new_state & SERIAL_STATE_FLAG_RUNNING_TIME_OVER) == 0) {
|
|
uint32_t tick_count = GetTickCount();
|
|
size_t cur_time = (tick_count - start_tick_count_) / 1000 / 60;
|
|
if (cur_time > s)
|
|
new_state |= SERIAL_STATE_FLAG_RUNNING_TIME_OVER;
|
|
}
|
|
if (data)
|
|
data->bRunningTime = s;
|
|
pos += 1;
|
|
break;
|
|
case SERIAL_CHUNK_PRODUCT_CODE:
|
|
if (state_ == SERIAL_STATE_FLAG_INVALID)
|
|
product_code_ = serial_->GetQWord(pos);
|
|
pos += 8;
|
|
break;
|
|
case SERIAL_CHUNK_MAX_BUILD:
|
|
uint32_t max_build_date;
|
|
max_build_date = serial_->GetDWord(pos);
|
|
if ((new_state & SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED) == 0) {
|
|
if (license_data_->GetDWord(FIELD_BUILD_DATE * sizeof(uint32_t)) > max_build_date)
|
|
new_state |= SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED;
|
|
}
|
|
if (data) {
|
|
data->dtMaxBuild.wYear = max_build_date >> 16;
|
|
data->dtMaxBuild.bMonth = static_cast<uint8_t>(max_build_date >> 8);
|
|
data->dtMaxBuild.bDay = static_cast<uint8_t>(max_build_date);
|
|
}
|
|
pos += 4;
|
|
break;
|
|
case SERIAL_CHUNK_USER_NAME:
|
|
s = serial_->GetByte(pos++);
|
|
if (data)
|
|
serial_->UTF8ToUnicode(pos, s, data->wUserName, _countof(data->wUserName));
|
|
pos += s;
|
|
break;
|
|
case SERIAL_CHUNK_EMAIL:
|
|
s = serial_->GetByte(pos++);
|
|
if (data)
|
|
serial_->UTF8ToUnicode(pos, s, data->wEMail, _countof(data->wEMail));
|
|
pos += s;
|
|
break;
|
|
case SERIAL_CHUNK_HWID:
|
|
s = serial_->GetByte(pos++);
|
|
if (state_ == SERIAL_STATE_FLAG_INVALID) {
|
|
HardwareID *hardware_id = Core::Instance()->hardware_id();
|
|
if (!hardware_id->IsCorrect(*serial_, pos, s))
|
|
return save_state(SERIAL_STATE_FLAG_BAD_HWID);
|
|
}
|
|
pos += s;
|
|
break;
|
|
case SERIAL_CHUNK_USER_DATA:
|
|
s = serial_->GetByte(pos++);
|
|
if (data) {
|
|
data->nUserDataLength = static_cast<uint8_t>(s);
|
|
for (size_t i = 0; i < s; i++) {
|
|
data->bUserData[i] = serial_->GetByte(pos + i);
|
|
}
|
|
}
|
|
pos += s;
|
|
break;
|
|
case SERIAL_CHUNK_END:
|
|
if (pos + 4 > serial_->size())
|
|
return save_state(SERIAL_STATE_FLAG_INVALID);
|
|
|
|
if (state_ == SERIAL_STATE_FLAG_INVALID) {
|
|
// calc hash without last chunk
|
|
SHA1 hash;
|
|
hash.Input(*serial_, start_, pos - start_ - 1);
|
|
|
|
// check CRC
|
|
const uint8_t *p = hash.Result();
|
|
for (size_t i = 0; i < 4; i++) {
|
|
if (serial_->GetByte(pos + i) != p[3 - i])
|
|
return save_state(SERIAL_STATE_FLAG_INVALID);
|
|
}
|
|
}
|
|
|
|
return save_state(new_state);
|
|
}
|
|
}
|
|
|
|
// SERIAL_CHUNK_END not found
|
|
return save_state(SERIAL_STATE_FLAG_INVALID);
|
|
}
|
|
|
|
int LicensingManager::GetSerialNumberState()
|
|
{
|
|
CriticalSection cs(critical_section_);
|
|
|
|
if (state_ & (SERIAL_STATE_FLAG_CORRUPTED | SERIAL_STATE_FLAG_INVALID | SERIAL_STATE_FLAG_BLACKLISTED | SERIAL_STATE_FLAG_BAD_HWID))
|
|
return state_; // no reasons to continue
|
|
|
|
return ParseSerial(NULL);
|
|
}
|
|
|
|
bool LicensingManager::GetSerialNumberData(VMProtectSerialNumberData *data, int size)
|
|
{
|
|
if (!data || size != sizeof(VMProtectSerialNumberData))
|
|
return false; // bad input
|
|
|
|
CriticalSection cs(critical_section_);
|
|
|
|
if (state_ == SERIAL_STATE_FLAG_CORRUPTED)
|
|
return false;
|
|
|
|
// clean memory
|
|
uint8_t *p = reinterpret_cast<uint8_t *>(data);
|
|
for (int i = 0; i < size; i++) {
|
|
p[i] = 0;
|
|
}
|
|
|
|
data->nState = (state_ & (SERIAL_STATE_FLAG_INVALID | SERIAL_STATE_FLAG_BLACKLISTED | SERIAL_STATE_FLAG_BAD_HWID)) ? state_ : ParseSerial(data);
|
|
return true;
|
|
}
|
|
|
|
int LicensingManager::ActivateLicense(const char *code, char *serial, int size) const
|
|
{
|
|
#ifdef WIN_DRIVER
|
|
return ACTIVATION_NOT_AVAILABLE;
|
|
#else
|
|
if (!CheckLicenseDataCRC())
|
|
return ACTIVATION_CORRUPTED;
|
|
|
|
ActivationRequest request;
|
|
int res = request.Process(*license_data_, code, false);
|
|
if (res == ACTIVATION_OK) {
|
|
int need = static_cast<int>(strlen(request.serial()));
|
|
if (need > size - 1)
|
|
return ACTIVATION_SMALL_BUFFER;
|
|
strncpy_s(serial, size, request.serial(), need);
|
|
}
|
|
return res;
|
|
#endif
|
|
}
|
|
|
|
int LicensingManager::DeactivateLicense(const char *serial) const
|
|
{
|
|
#ifdef WIN_DRIVER
|
|
return ACTIVATION_NOT_AVAILABLE;
|
|
#else
|
|
if (!CheckLicenseDataCRC())
|
|
return ACTIVATION_CORRUPTED;
|
|
|
|
DeactivationRequest request;
|
|
return request.Process(*license_data_, serial, false);
|
|
#endif
|
|
}
|
|
|
|
int LicensingManager::GetOfflineActivationString(const char *code, char *buf, int size) const
|
|
{
|
|
#ifdef WIN_DRIVER
|
|
return ACTIVATION_NOT_AVAILABLE;
|
|
#else
|
|
if (!buf || size <= 0)
|
|
return ACTIVATION_SMALL_BUFFER;
|
|
|
|
if (!CheckLicenseDataCRC())
|
|
return ACTIVATION_CORRUPTED;
|
|
|
|
ActivationRequest request;
|
|
int res = request.Process(*license_data_, code, true);
|
|
if (res == ACTIVATION_OK) {
|
|
int need = static_cast<int>(strlen(request.url()));
|
|
if (need > size - 1)
|
|
return ACTIVATION_SMALL_BUFFER;
|
|
strncpy_s(buf, size, request.url(), need);
|
|
}
|
|
return res;
|
|
#endif
|
|
}
|
|
|
|
int LicensingManager::GetOfflineDeactivationString(const char *serial, char *buf, int size) const
|
|
{
|
|
#ifdef WIN_DRIVER
|
|
return ACTIVATION_NOT_AVAILABLE;
|
|
#else
|
|
if (!buf || size <= 0)
|
|
return ACTIVATION_SMALL_BUFFER;
|
|
|
|
if (!CheckLicenseDataCRC())
|
|
return ACTIVATION_CORRUPTED;
|
|
|
|
DeactivationRequest request;
|
|
int res = request.Process(*license_data_, serial, true);
|
|
if (res == ACTIVATION_OK) {
|
|
int need = static_cast<int>(strlen(request.url()));
|
|
if (need > size - 1)
|
|
return ACTIVATION_SMALL_BUFFER;
|
|
strncpy_s(buf, size, request.url(), need);
|
|
}
|
|
return res;
|
|
#endif
|
|
}
|
|
|
|
void LicensingManager::DecryptBuffer(uint8_t *buffer)
|
|
{
|
|
uint32_t key0 = static_cast<uint32_t>(product_code_);
|
|
uint32_t key1 = static_cast<uint32_t>(product_code_ >> 32) + session_key_;
|
|
uint32_t *p = reinterpret_cast<uint32_t*>(buffer);
|
|
|
|
p[0] = _rotl32((p[0] + session_key_) ^ key0, 7) + key1;
|
|
p[1] = _rotl32((p[1] + session_key_) ^ key0, 11) + key1;
|
|
p[2] = _rotl32((p[2] + session_key_) ^ key0, 17) + key1;
|
|
p[3] = _rotl32((p[3] + session_key_) ^ key0, 23) + key1;
|
|
|
|
if (p[0] + p[1] + p[2] + p[3] != session_key_ * 4) {
|
|
const VMP_CHAR *message;
|
|
#ifdef VMP_GNU
|
|
message = VMProtectDecryptStringA(MESSAGE_SERIAL_NUMBER_REQUIRED_STR);
|
|
#else
|
|
message = VMProtectDecryptStringW(MESSAGE_SERIAL_NUMBER_REQUIRED_STR);
|
|
#endif
|
|
if (message[0])
|
|
ShowMessage(message);
|
|
|
|
#if defined(VMP_GNU)
|
|
exit(0xDEADC0DE);
|
|
#elif defined(WIN_DRIVER)
|
|
DbgBreakPointWithStatus(0xDEADC0DE);
|
|
#else
|
|
TerminateProcess(GetCurrentProcess(), 0xDEADC0DE);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifndef WIN_DRIVER
|
|
|
|
/**
|
|
* BaseRequest
|
|
*/
|
|
|
|
BaseRequest::BaseRequest()
|
|
: response_(NULL)
|
|
{
|
|
url_[0] = 0;
|
|
}
|
|
|
|
BaseRequest::~BaseRequest()
|
|
{
|
|
delete [] response_;
|
|
}
|
|
|
|
bool BaseRequest::BuildUrl(const CryptoContainer &license_data)
|
|
{
|
|
size_t url_size = license_data.GetDWord(FIELD_ACTIVATION_URL_SIZE * sizeof(uint32_t));
|
|
if (!url_size)
|
|
return false;
|
|
|
|
size_t url_offset = license_data.GetDWord(FIELD_ACTIVATION_URL_OFFSET * sizeof(uint32_t));
|
|
for (size_t i = 0; i < url_size; i++) {
|
|
url_[i] = license_data.GetByte(url_offset + i);
|
|
}
|
|
if (url_[url_size] != '/')
|
|
url_[url_size++] = '/';
|
|
url_[url_size] = 0;
|
|
return true;
|
|
}
|
|
|
|
#ifdef __unix__
|
|
static size_t curl_write_data(void *ptr, size_t size, size_t nmemb, void *stream)
|
|
{
|
|
size_t written = size * nmemb;
|
|
|
|
std::string *dest = (std::string *)stream;
|
|
*dest += std::string((char *)ptr, written);
|
|
return written;
|
|
}
|
|
static size_t curl_header(void *ptr, size_t size, size_t nmemb, void *stream)
|
|
{
|
|
size_t written = size * nmemb;
|
|
|
|
if(strncmp((char*)ptr, "Date: ", 6) == 0)
|
|
{
|
|
*((time_t *)stream) = curl_getdate((char *)ptr + 6, NULL);
|
|
}
|
|
return written;
|
|
}
|
|
#endif
|
|
|
|
bool BaseRequest::Send()
|
|
{
|
|
if (response_) {
|
|
delete [] response_;
|
|
response_ = NULL;
|
|
}
|
|
|
|
#ifdef __APPLE__
|
|
CFStringRef str_ref = CFStringCreateWithCString(NULL, url_, kCFStringEncodingMacRoman);
|
|
CFURLRef url_ref = CFURLCreateWithString(kCFAllocatorDefault, str_ref, NULL);
|
|
CFHTTPMessageRef req_ref = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), url_ref, kCFHTTPVersion1_1);
|
|
CFReadStreamRef stream_ref = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, req_ref);
|
|
|
|
CFReadStreamOpen(stream_ref);
|
|
int current;
|
|
int size = 8096;
|
|
response_ = new char[size];
|
|
CFIndex read_size;
|
|
for (current = 0; current < size; current += read_size) {
|
|
read_size = CFReadStreamRead(stream_ref, reinterpret_cast<uint8_t *>(response_ + current), size - current);
|
|
if (read_size < 0)
|
|
break; // error
|
|
if (!read_size)
|
|
break; // end of data
|
|
}
|
|
if (current < size)
|
|
response_[current] = 0;
|
|
bool res = current > 0 && current < size;
|
|
|
|
CFHTTPMessageRef resp = (CFHTTPMessageRef)CFReadStreamCopyProperty(stream_ref, kCFStreamPropertyHTTPResponseHeader);
|
|
if(resp)
|
|
{
|
|
CFStringRef dateHeaderRef = CFHTTPMessageCopyHeaderFieldValue(resp, CFSTR("Date"));
|
|
if (dateHeaderRef != NULL)
|
|
{
|
|
CFGregorianDate gdate;
|
|
CFIndex count = _CFGregorianDateCreateWithString(kCFAllocatorDefault, dateHeaderRef, &gdate, NULL);
|
|
if (count != 0)
|
|
loader_data->set_server_date((gdate.year << 16) + (static_cast<uint8_t>(gdate.month) << 8) + static_cast<uint8_t>(gdate.day));
|
|
CFRelease(dateHeaderRef);
|
|
}
|
|
CFRelease(resp);
|
|
}
|
|
CFReadStreamClose(stream_ref);
|
|
|
|
CFRelease(stream_ref);
|
|
CFRelease(req_ref);
|
|
CFRelease(url_ref);
|
|
CFRelease(str_ref);
|
|
|
|
return res;
|
|
#elif defined(__unix__)
|
|
CURL *curl = curl_easy_init();
|
|
if (curl) {
|
|
curl_easy_setopt(curl, CURLOPT_URL, url_);
|
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data);
|
|
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_header);
|
|
std::string dest;
|
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &dest);
|
|
time_t file_time = (time_t)-1;
|
|
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &file_time);
|
|
CURLcode c = curl_easy_perform(curl);
|
|
if (c == CURLE_OK) {
|
|
response_ = strdup(dest.c_str());
|
|
if (file_time != (time_t)-1) {
|
|
struct tm local_tm;
|
|
tm *t = localtime_r(&file_time, &local_tm);
|
|
if (t)
|
|
loader_data->set_server_date(((1900 + t->tm_year) << 16) + (static_cast<uint8_t>(t->tm_mon + 1) << 8) + static_cast<uint8_t>(t->tm_mday));
|
|
}
|
|
}
|
|
curl_easy_cleanup(curl);
|
|
return (c == CURLE_OK);
|
|
}
|
|
return false;
|
|
#else
|
|
HMODULE dll = LoadLibraryA(VMProtectDecryptStringA("winhttp.dll"));
|
|
if (!dll)
|
|
return false;
|
|
|
|
typedef HINTERNET (WINAPI *HTTP_OPEN)(LPCWSTR lpszAgent, DWORD dwAccessType, LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags);
|
|
typedef BOOL (WINAPI *HTTP_CLOSE_HANDLE)(HINTERNET hInternet);
|
|
typedef BOOL (WINAPI *HTTP_READ_DATA)(HINTERNET hFile, LPVOID lpBuffer, DWORD dwNumberOfBytesToRead, LPDWORD lpdwNumberOfBytesRead);
|
|
typedef BOOL (WINAPI *HTTP_CRACK_URL)(LPCWSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags, LPURL_COMPONENTS lpUrlComponents);
|
|
typedef HINTERNET (WINAPI *HTTP_CONNECT)(HINTERNET hInternet, LPCWSTR lpszServerName, INTERNET_PORT nServerPort, DWORD dwReserved);
|
|
typedef BOOL (WINAPI *HTTP_SETCREDENTIALS)(HINTERNET hRequest, DWORD AuthTargets, DWORD AuthScheme, LPCWSTR pszUserName, LPCWSTR pszPassword, LPVOID pAuthParams);
|
|
typedef HINTERNET (WINAPI *HTTP_OPEN_REQUEST)(HINTERNET hConnect, LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion, LPCWSTR lpszReferer, LPCWSTR *lplpszAcceptTypes, DWORD dwFlags);
|
|
typedef BOOL (WINAPI *HTTP_SEND_REQUEST)(HINTERNET hRequest, LPCWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext);
|
|
typedef BOOL (WINAPI *HTTP_RECEIVE_RESPONSE)(HINTERNET hRequest, LPVOID lpReserved);
|
|
typedef BOOL (WINAPI *HTTP_SET_OPTION)(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength);
|
|
typedef BOOL (WINAPI *HTTP_GET_IE_PROXY_CONFIG)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *pProxyConfig);
|
|
typedef BOOL(WINAPI *HTTP_QUERY_HEADERS)(HINTERNET hRequest, DWORD dwInfoLevel, LPCWSTR pwszName, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex);
|
|
|
|
HTTP_OPEN http_open = reinterpret_cast<HTTP_OPEN>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpOpen")));
|
|
HTTP_READ_DATA http_read_data = reinterpret_cast<HTTP_READ_DATA>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpReadData")));
|
|
HTTP_CLOSE_HANDLE http_close_handle = reinterpret_cast<HTTP_CLOSE_HANDLE>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpCloseHandle")));
|
|
HTTP_CRACK_URL http_crack_url = reinterpret_cast<HTTP_CRACK_URL>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpCrackUrl")));
|
|
HTTP_CONNECT http_connect = reinterpret_cast<HTTP_CONNECT>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpConnect")));
|
|
HTTP_SETCREDENTIALS http_setcredentials = reinterpret_cast<HTTP_SETCREDENTIALS>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpSetCredentials")));
|
|
HTTP_OPEN_REQUEST http_open_request = reinterpret_cast<HTTP_OPEN_REQUEST>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpOpenRequest")));
|
|
HTTP_SEND_REQUEST http_send_request = reinterpret_cast<HTTP_SEND_REQUEST>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpSendRequest")));
|
|
HTTP_RECEIVE_RESPONSE http_receive_response = reinterpret_cast<HTTP_RECEIVE_RESPONSE>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpReceiveResponse")));
|
|
HTTP_SET_OPTION http_set_option = reinterpret_cast<HTTP_SET_OPTION>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpSetOption")));
|
|
HTTP_GET_IE_PROXY_CONFIG http_get_ie_proxy_config = reinterpret_cast<HTTP_GET_IE_PROXY_CONFIG>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpGetIEProxyConfigForCurrentUser")));
|
|
HTTP_QUERY_HEADERS http_query_headers = reinterpret_cast<HTTP_QUERY_HEADERS>(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpQueryHeaders")));
|
|
|
|
bool res = false;
|
|
if (http_open
|
|
&& http_read_data
|
|
&& http_close_handle
|
|
&& http_crack_url
|
|
&& http_connect
|
|
&& http_setcredentials
|
|
&& http_open_request
|
|
&& http_send_request
|
|
&& http_receive_response
|
|
&& http_set_option
|
|
&& http_query_headers) {
|
|
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_proxy_config = WINHTTP_CURRENT_USER_IE_PROXY_CONFIG();
|
|
if (http_get_ie_proxy_config)
|
|
http_get_ie_proxy_config(&ie_proxy_config);
|
|
// We are not using WPAD directly, it is buggy (OLE actively used and may hung).
|
|
DWORD dwAccessType = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; // default: settings from global registry, 8.1+ deprecated.
|
|
#ifdef _WIN64
|
|
PEB64 *peb = reinterpret_cast<PEB64 *>(__readgsqword(0x60));
|
|
#else
|
|
PEB32 *peb = reinterpret_cast<PEB32 *>(__readfsdword(0x30));
|
|
#endif
|
|
uint16_t os_build_number = peb->OSBuildNumber;
|
|
if (os_build_number >= WINDOWS_8_1)
|
|
dwAccessType = 4; // WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY - 8.1+: smart from user IE config and/or global registry
|
|
|
|
if (ie_proxy_config.lpszProxy)
|
|
dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; // IE manual proxy setup
|
|
HINTERNET inet = http_open(VMProtectDecryptStringW(L"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"), dwAccessType, ie_proxy_config.lpszProxy, ie_proxy_config.lpszProxyBypass, 0);
|
|
if (inet) {
|
|
URL_COMPONENTS components = URL_COMPONENTS();
|
|
|
|
components.dwStructSize = sizeof(components);
|
|
#define INTERNET_MAX_HOST_NAME_LENGTH 256
|
|
#define INTERNET_MAX_USER_NAME_LENGTH 128
|
|
#define INTERNET_MAX_PASSWORD_LENGTH 128
|
|
#define INTERNET_MAX_PATH_LENGTH 2048
|
|
wchar_t url_host[INTERNET_MAX_HOST_NAME_LENGTH];
|
|
wchar_t url_path[INTERNET_MAX_PATH_LENGTH];
|
|
wchar_t url_user[INTERNET_MAX_USER_NAME_LENGTH];
|
|
wchar_t url_password[INTERNET_MAX_PASSWORD_LENGTH];
|
|
components.lpszHostName = url_host;
|
|
components.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
|
|
components.lpszUserName = url_user;
|
|
components.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
|
|
components.lpszPassword = url_password;
|
|
components.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH;
|
|
components.lpszUrlPath = url_path;
|
|
components.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
|
|
http_crack_url(std::wstring(url_, url_ + strlen(url_)).c_str(), 0, 0, &components);
|
|
|
|
HINTERNET h = 0;
|
|
HINTERNET connect = http_connect(inet, components.lpszHostName, components.nPort, 0);
|
|
if (connect) {
|
|
h = http_open_request(connect, L"GET", components.lpszUrlPath, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_BYPASS_PROXY_CACHE | (
|
|
(components.nScheme == INTERNET_SCHEME_HTTPS) ? WINHTTP_FLAG_SECURE : 0
|
|
));
|
|
if (h) {
|
|
//TODO: internet_setcredentials if need
|
|
if (components.nScheme == INTERNET_SCHEME_HTTPS) {
|
|
DWORD data = SECURITY_FLAG_IGNORE_UNKNOWN_CA
|
|
| SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
|
| SECURITY_FLAG_IGNORE_CERT_CN_INVALID
|
|
/*| SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE*/;
|
|
http_set_option(h, WINHTTP_OPTION_SECURITY_FLAGS, &data, sizeof(data));
|
|
}
|
|
if (!http_send_request(h, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, NULL) || !http_receive_response( h, NULL)) {
|
|
http_close_handle(h);
|
|
h = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (h) {
|
|
DWORD current;
|
|
DWORD size = 8096;
|
|
response_ = new char[size];
|
|
DWORD read_size;
|
|
for (current = 0; current < size; current += read_size) {
|
|
if (http_read_data(h, response_ + current, size - current, &read_size) != TRUE)
|
|
break; // error
|
|
if (!read_size)
|
|
break; // end of data
|
|
}
|
|
if (current < size)
|
|
response_[current] = 0;
|
|
res = current > 0 && current < size;
|
|
SYSTEMTIME dtBuf;
|
|
DWORD dtBufLength = sizeof(dtBuf);
|
|
if(http_query_headers(h, WINHTTP_QUERY_DATE | WINHTTP_QUERY_FLAG_SYSTEMTIME, WINHTTP_HEADER_NAME_BY_INDEX, &dtBuf, &dtBufLength, WINHTTP_NO_HEADER_INDEX)) {
|
|
FILETIME ft;
|
|
SystemTimeToFileTime(&dtBuf, &ft);
|
|
FileTimeToSystemTime(&ft, &dtBuf);
|
|
loader_data->set_server_date((dtBuf.wYear << 16) + (static_cast<uint8_t>(dtBuf.wMonth) << 8) + static_cast<uint8_t>(dtBuf.wDay));
|
|
}
|
|
http_close_handle(h);
|
|
}
|
|
if (connect)
|
|
http_close_handle(connect);
|
|
http_close_handle(inet);
|
|
}
|
|
|
|
if (ie_proxy_config.lpszAutoConfigUrl)
|
|
GlobalFree(ie_proxy_config.lpszAutoConfigUrl);
|
|
if (ie_proxy_config.lpszProxy)
|
|
GlobalFree(ie_proxy_config.lpszProxy);
|
|
if (ie_proxy_config.lpszProxyBypass)
|
|
GlobalFree(ie_proxy_config.lpszProxyBypass);
|
|
}
|
|
FreeLibrary(dll);
|
|
return res;
|
|
#endif
|
|
}
|
|
|
|
void BaseRequest::AppendUrlParam(const char *param, const char *value)
|
|
{
|
|
AppendUrl(param, false);
|
|
AppendUrl(value, true);
|
|
}
|
|
|
|
void BaseRequest::AppendUrl(const char *str, bool escape)
|
|
{
|
|
size_t pos = 0;
|
|
while (url_[pos]) {
|
|
pos++;
|
|
}
|
|
|
|
size_t size = _countof(url_);
|
|
if (escape) {
|
|
while (*str && pos < size - 1 - 3)
|
|
{
|
|
uint8_t c = *str;
|
|
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
|
|
url_[pos++] = c;
|
|
} else if (c == ' ') {
|
|
url_[pos++] = '+';
|
|
} else {
|
|
const char *hex = "0123456789abcdef";
|
|
url_[pos++] = '%';
|
|
url_[pos++] = hex[c >> 4];
|
|
url_[pos++] = hex[c & 0x0f];
|
|
}
|
|
str++;
|
|
}
|
|
} else {
|
|
while (*str && pos < size) {
|
|
url_[pos++] = *str;
|
|
str++;
|
|
}
|
|
}
|
|
url_[pos] = 0;
|
|
}
|
|
|
|
void BaseRequest::EncodeUrl()
|
|
{
|
|
char buf[2048];
|
|
strcpy_s(buf, url_);
|
|
size_t url_size = sizeof(url_);
|
|
Base64Encode(reinterpret_cast<const uint8_t *>(buf), strlen(buf), url_, url_size);
|
|
url_[url_size] = 0;
|
|
}
|
|
|
|
/**
|
|
* ActivationRequest
|
|
*/
|
|
|
|
ActivationRequest::ActivationRequest()
|
|
: BaseRequest(), serial_(NULL)
|
|
{
|
|
|
|
}
|
|
|
|
bool ActivationRequest::VerifyCode(const char *code) const
|
|
{
|
|
if (!code || !code[0])
|
|
return false;
|
|
|
|
static const char *alphabet = "0123456789abcdefghijklmnopqrstuvwxyz-";
|
|
for (const char *p = code; *p; p++) {
|
|
if (!strchr(alphabet, tolower(*p)))
|
|
return false;
|
|
if (p - code > 32)
|
|
return false; // too long
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ActivationRequest::BuildUrl(const CryptoContainer &license_data, const char *code, bool offline)
|
|
{
|
|
if (!offline) {
|
|
if (!BaseRequest::BuildUrl(license_data))
|
|
return false;
|
|
}
|
|
|
|
// hwid -> base64
|
|
char str_hwid[100];
|
|
{
|
|
uint8_t hwid[16 * sizeof(uint32_t)]; // HardwareID::MAX_BLOCKS
|
|
|
|
size_t hwid_size = Core::Instance()->hardware_id()->Copy(hwid, sizeof(hwid));
|
|
size_t dest_len = sizeof(str_hwid);
|
|
Base64Encode(hwid, hwid_size, str_hwid, dest_len);
|
|
str_hwid[dest_len] = 0;
|
|
}
|
|
|
|
// hash -> base64
|
|
char str_hash[64];
|
|
{
|
|
SHA1 sha;
|
|
sha.Input(license_data, license_data.GetDWord(FIELD_MODULUS_OFFSET * sizeof(uint32_t)), license_data.GetDWord(FIELD_MODULUS_SIZE * sizeof(uint32_t)));
|
|
size_t dest_len = sizeof(str_hash);
|
|
Base64Encode(sha.Result(), 20, str_hash, dest_len);
|
|
str_hash[dest_len] = 0;
|
|
}
|
|
|
|
// build url
|
|
if (offline) {
|
|
char str[] = {'t', 'y', 'p', 'e', '=', 'a', 'c', 't', 'i', 'v', 'a', 't', 'i', 'o', 'n', '&', 'c', 'o', 'd', 'e', '=', 0};
|
|
AppendUrlParam(str, code);
|
|
} else {
|
|
char str[] = {'a', 'c', 't', 'i', 'v', 'a', 't', 'i', 'o', 'n', '.', 'p', 'h', 'p', '?', 'c', 'o', 'd', 'e', '=', 0};
|
|
AppendUrlParam(str, code);
|
|
}
|
|
{
|
|
char str[] = {'&', 'h', 'w', 'i', 'd', '=', 0};
|
|
AppendUrlParam(str, str_hwid);
|
|
}
|
|
{
|
|
char str[] = {'&', 'h', 'a', 's', 'h', '=', 0};
|
|
AppendUrlParam(str, str_hash);
|
|
}
|
|
|
|
if (offline)
|
|
EncodeUrl();
|
|
|
|
return true;
|
|
}
|
|
|
|
int ActivationRequest::Process(const CryptoContainer &license_data, const char *code, bool offline)
|
|
{
|
|
if (!VerifyCode(code))
|
|
return ACTIVATION_BAD_CODE;
|
|
|
|
if (!BuildUrl(license_data, code, offline))
|
|
return ACTIVATION_NOT_AVAILABLE;
|
|
|
|
if (offline)
|
|
return ACTIVATION_OK;
|
|
|
|
if (!Send())
|
|
return ACTIVATION_NO_CONNECTION;
|
|
|
|
const char *res = response();
|
|
if (!res || !res[0])
|
|
return ACTIVATION_BAD_REPLY;
|
|
|
|
// possible answers: OK, BAD, BANNED, USED, EXPIRED
|
|
// if OK - see the serial number below
|
|
|
|
if (res[0] == 'B' && res[1] == 'A' && res[2] == 'D' && res[3] == 0)
|
|
return ACTIVATION_BAD_CODE;
|
|
|
|
if (res[0] == 'B' && res[1] == 'A' && res[2] == 'N' && res[3] == 'N' && res[4] == 'E' && res[5] == 'D' && res[6] == 0)
|
|
return ACTIVATION_BANNED;
|
|
|
|
if (res[0] == 'U' && res[1] == 'S' && res[2] == 'E' && res[3] == 'D' && res[4] == 0)
|
|
return ACTIVATION_ALREADY_USED;
|
|
|
|
if (res[0] == 'E' && res[1] == 'X' && res[2] == 'P' && res[3] == 'I' && res[4] == 'R' && res[5] == 'E' && res[6] == 'D' && res[7] == 0)
|
|
return ACTIVATION_EXPIRED;
|
|
|
|
const char *endl = strchr(res, '\n');
|
|
if (!endl)
|
|
return ACTIVATION_BAD_REPLY;
|
|
|
|
if (endl - res != 2)
|
|
return ACTIVATION_BAD_REPLY;
|
|
|
|
if (res[0] != 'O' || res[1] != 'K')
|
|
return ACTIVATION_BAD_REPLY;
|
|
|
|
size_t len = strlen(res + 3);
|
|
if (len < 64)
|
|
return ACTIVATION_BAD_REPLY;
|
|
|
|
serial_ = res + 3;
|
|
return ACTIVATION_OK;
|
|
}
|
|
|
|
/**
|
|
* DeactivationRequest
|
|
*/
|
|
|
|
bool DeactivationRequest::VerifySerial(const char *serial) const
|
|
{
|
|
if (!serial || !serial[0])
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DeactivationRequest::BuildUrl(const CryptoContainer &license_data, const char *serial, bool offline)
|
|
{
|
|
if (!offline) {
|
|
if (!BaseRequest::BuildUrl(license_data))
|
|
return false;
|
|
}
|
|
|
|
size_t code_len = strlen(serial);
|
|
size_t len = code_len;
|
|
uint8_t *p = new uint8_t[len];
|
|
if (!Base64Decode(serial, code_len, p, len)) {
|
|
delete [] p;
|
|
return false;
|
|
}
|
|
|
|
// get binary hash
|
|
char str_hash[64];
|
|
{
|
|
SHA1 sha;
|
|
sha.Input(p, len);
|
|
size_t dst_len = sizeof(str_hash);
|
|
Base64Encode(sha.Result(), 20, str_hash, dst_len);
|
|
str_hash[dst_len] = 0;
|
|
}
|
|
delete [] p;
|
|
|
|
if (offline) {
|
|
char str[] = { 't', 'y', 'p', 'e', '=', 'd', 'e', 'a', 'c', 't', 'i', 'v', 'a', 't', 'i', 'o', 'n', '&', 'h', 'a', 's', 'h', '=', 0 };
|
|
AppendUrlParam(str, str_hash);
|
|
}
|
|
else {
|
|
char str[] = { 'd', 'e', 'a', 'c', 't', 'i', 'v', 'a', 't', 'i', 'o', 'n', '.', 'p', 'h', 'p', '?', 'h', 'a', 's', 'h', '=', 0 };
|
|
AppendUrlParam(str, str_hash);
|
|
}
|
|
|
|
if (offline)
|
|
EncodeUrl();
|
|
|
|
return true;
|
|
}
|
|
|
|
int DeactivationRequest::Process(const CryptoContainer &license_data, const char *serial, bool offline)
|
|
{
|
|
if (!VerifySerial(serial))
|
|
return ACTIVATION_BAD_CODE;
|
|
|
|
if (!BuildUrl(license_data, serial, offline))
|
|
return ACTIVATION_NOT_AVAILABLE;
|
|
|
|
if (offline)
|
|
return ACTIVATION_OK;
|
|
|
|
if (!Send())
|
|
return ACTIVATION_NO_CONNECTION;
|
|
|
|
const char *res = response();
|
|
if (!res || !res[0])
|
|
return ACTIVATION_BAD_REPLY;
|
|
|
|
if (res[0] == 'O' && res[1] == 'K' && res[2] == 0)
|
|
return ACTIVATION_OK;
|
|
|
|
if (res[0] == 'E' && res[1] == 'R' && res[2] == 'R' && res[3] == 'O' && res[4] == 'R' && res[5] == 0)
|
|
return ACTIVATION_CORRUPTED;
|
|
|
|
if (res[0] == 'U' && res[1] == 'N' && res[2] == 'K' && res[3] == 'N' && res[4] == 'O' && res[5] == 'W' && res[6] == 'N' && res[7] == 0)
|
|
return ACTIVATION_SERIAL_UNKNOWN;
|
|
|
|
return ACTIVATION_BAD_REPLY;
|
|
};
|
|
|
|
#endif |