#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 #include #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 #else #ifndef WIN_DRIVER #include #include #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((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(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(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(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(timeinfo->tm_mon + 1) << 8) + static_cast(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(time_fields.Month) << 8) + static_cast(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(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(total_days_since_1601 / 146097); total_days_since_1601 -= number_of_400s * 146097; uint32_t number_of_100s = static_cast((total_days_since_1601 * 100 + 75) / 3652425); total_days_since_1601 -= number_of_100s * 36524; uint32_t number_of_4s = static_cast(total_days_since_1601 / 1461); total_days_since_1601 -= number_of_4s * 1461; uint16_t year = static_cast((total_days_since_1601 * 100 + 75) / 36525); total_days_since_1601 -= 365 * year; year = static_cast((number_of_400s * 400) + (number_of_100s * 100) + (number_of_4s * 4) + year + 1601); uint16_t day = static_cast(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(month) << 8) + static_cast(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(exp_date >> 8); data->dtExpire.bDay = static_cast(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(max_build_date >> 8); data->dtMaxBuild.bDay = static_cast(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(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(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(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(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(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(product_code_); uint32_t key1 = static_cast(product_code_ >> 32) + session_key_; uint32_t *p = reinterpret_cast(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(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(gdate.month) << 8) + static_cast(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(t->tm_mon + 1) << 8) + static_cast(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(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpOpen"))); HTTP_READ_DATA http_read_data = reinterpret_cast(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpReadData"))); HTTP_CLOSE_HANDLE http_close_handle = reinterpret_cast(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpCloseHandle"))); HTTP_CRACK_URL http_crack_url = reinterpret_cast(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpCrackUrl"))); HTTP_CONNECT http_connect = reinterpret_cast(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpConnect"))); HTTP_SETCREDENTIALS http_setcredentials = reinterpret_cast(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpSetCredentials"))); HTTP_OPEN_REQUEST http_open_request = reinterpret_cast(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpOpenRequest"))); HTTP_SEND_REQUEST http_send_request = reinterpret_cast(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpSendRequest"))); HTTP_RECEIVE_RESPONSE http_receive_response = reinterpret_cast(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpReceiveResponse"))); HTTP_SET_OPTION http_set_option = reinterpret_cast(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpSetOption"))); HTTP_GET_IE_PROXY_CONFIG http_get_ie_proxy_config = reinterpret_cast(InternalGetProcAddress(dll, VMProtectDecryptStringA("WinHttpGetIEProxyConfigForCurrentUser"))); HTTP_QUERY_HEADERS http_query_headers = reinterpret_cast(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(__readgsqword(0x60)); #else PEB32 *peb = reinterpret_cast(__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(dtBuf.wMonth) << 8) + static_cast(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(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