VMProtect/runtime/hwid.cc

688 lines
21 KiB
C++
Raw Normal View History

2023-05-14 16:21:09 +03:00
#include "common.h"
#include "objects.h"
#include "utils.h"
#include "hwid.h"
#include "core.h"
#include "crypto.h"
#ifdef __unix__
#include <mntent.h>
#include <dirent.h>
#include <net/if.h>
#include <pthread.h>
#endif
#ifdef VMP_GNU
EXPORT_API int WINAPI ExportedGetCurrentHWID(char *buffer, int size) __asm__ ("ExportedGetCurrentHWID");
#endif
#ifdef WIN_DRIVER
#include <ntddndis.h>
extern "C" {
NTSYSAPI
NTSTATUS
NTAPI
ZwCreateEvent (
PHANDLE EventHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
EVENT_TYPE EventType,
BOOLEAN InitialState
);
NTSYSAPI
NTSTATUS
NTAPI
ZwWaitForSingleObject(
HANDLE Handle,
BOOLEAN Alertable,
PLARGE_INTEGER Timeout
);
}
#endif
int WINAPI ExportedGetCurrentHWID(char *buffer, int size)
{
HardwareID *hardware_id = Core::Instance()->hardware_id();
return hardware_id ? hardware_id->GetCurrent(buffer, size) : 0;
}
/**
* HardwareID
*/
#ifdef WIN_DRIVER
bool GetRegValue(LPCWSTR reg_path, LPCWSTR value_name, LPWSTR buffer, size_t *size)
{
UNICODE_STRING unicode_reg_path, unicode_value_name;
OBJECT_ATTRIBUTES object_attributes;
NTSTATUS status;
HANDLE key_handle;
ULONG information_size;
KEY_VALUE_PARTIAL_INFORMATION *information;
bool res = false;
RtlInitUnicodeString(&unicode_reg_path, reg_path);
RtlInitUnicodeString(&unicode_value_name, value_name);
InitializeObjectAttributes(&object_attributes, &unicode_reg_path, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwOpenKey(&key_handle, KEY_QUERY_VALUE, &object_attributes);
if (NT_SUCCESS(status)) {
information_size = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH * sizeof(WCHAR);
information = reinterpret_cast<KEY_VALUE_PARTIAL_INFORMATION*>(new uint8_t[information_size]);
status = ZwQueryValueKey(key_handle, &unicode_value_name, KeyValuePartialInformation, information, information_size, &information_size);
if (NT_SUCCESS(status)) {
size_t len = information->DataLength / sizeof(wchar_t);
if (*size < len + 1) {
*size = len + 1;
} else {
RtlCopyMemory(buffer, information->Data, information->DataLength);
buffer[len] = 0;
*size = wcslen(buffer);
res = true;
}
}
delete [] information;
ZwClose(key_handle);
}
return res;
}
#endif
HardwareID::HardwareID()
: block_count_(0), start_block_(0)
{
uint64_t timestamp = __rdtsc(); // exactly 8 bytes
timestamp ^= ~timestamp << 32; // remove zeroes at the beginning
blocks_ = new CryptoContainer(sizeof(uint32_t) * MAX_BLOCKS, reinterpret_cast<uint8_t *>(&timestamp));
// old methods
GetCPU(0);
GetCPU(1);
start_block_ = block_count_;
// new methods, we'll return HWID starting from this DWORD
GetCPU(2);
GetMachineName();
GetHDD();
GetMacAddresses();
}
HardwareID::~HardwareID()
{
delete blocks_;
}
void HardwareID::AddBlock(const void *p, size_t size, BlockType type)
{
if (block_count_ == MAX_BLOCKS) return; // no free space
SHA1 hash;
hash.Input(reinterpret_cast<const uint8_t *>(p), size);
uint32_t block = __builtin_bswap32(*reinterpret_cast<const uint32_t *>(hash.Result()));
block &= ~TYPE_MASK; // zero two lower bits
block |= type & TYPE_MASK; // set type bits
// check existing blocks
for (size_t i = block_count_; i > start_block_; i--) {
uint32_t prev_block = blocks_->GetDWord((i - 1) * sizeof(uint32_t));
if (prev_block == block)
return;
if ((prev_block & TYPE_MASK) != (block & TYPE_MASK))
break;
}
blocks_->SetDWord(block_count_ * sizeof(uint32_t), block);
block_count_++;
}
void HardwareID::GetCPU(uint8_t method)
{
uint32_t old_block_count = block_count_;
#ifdef WIN_DRIVER
KAFFINITY system_mask = KeQueryActiveProcessors();
KAFFINITY mask = 1;
#endif
#ifdef VMP_GNU
// set process affinity mask to system affinity mask
#ifdef __APPLE__
//FIXME
if (0) {
#else
cpu_set_t process_mask, system_mask;
memset(&system_mask, 0xFF, sizeof(system_mask));
if (0 == sched_getaffinity(0, sizeof(process_mask), &process_mask)) {
sched_setaffinity(0, sizeof(system_mask), &system_mask); //try all CPUs, will set MAX CPUs
sched_getaffinity(0, sizeof(system_mask), &system_mask); //get MAX CPUs
#endif
#else
#ifndef WIN_DRIVER
DWORD_PTR process_mask, system_mask;
HANDLE process = GetCurrentProcess();
if (GetProcessAffinityMask(process, &process_mask, &system_mask)) {
if (process_mask != system_mask)
SetProcessAffinityMask(process, system_mask);
DWORD_PTR mask = 1;
HANDLE thread = GetCurrentThread();
#endif
#endif
#ifdef VMP_GNU
// set thread affinity mask to mask
#ifdef __APPLE__
//FIXME
while (false) {
if (false) {
#else
for (size_t i = 0; i < sizeof(system_mask) * 8; i++) {
if (__CPU_ISSET_S(i, sizeof(system_mask), &system_mask)) {
cpu_set_t mask;
__CPU_ZERO_S(sizeof(mask), &mask);
__CPU_SET_S(i, sizeof(mask), &mask);
sched_setaffinity(0, sizeof(mask), &mask);
#endif
#else
for (size_t i = 0; i < sizeof(mask) * 8; i++) {
if (system_mask & mask) {
#ifdef WIN_DRIVER
KeSetSystemAffinityThread(mask);
#else
DWORD_PTR old_mask = SetThreadAffinityMask(thread, mask);
Sleep(0);
#endif
#endif
ProcessCPU(method);
#ifdef VMP_GNU
// set thread affinity mask back to old_mask
#ifdef __APPLE__
//FIXME
#else
//do nothing
#endif
#else
#ifdef WIN_DRIVER
KeRevertToUserAffinityThread();
#else
SetThreadAffinityMask(thread, old_mask);
#endif
#endif
}
#ifndef VMP_GNU
mask <<= 1;
#endif
}
#ifndef WIN_DRIVER
#ifdef VMP_GNU
// set process affinity mask back to process_mask
#ifdef __APPLE__
//FIXME
#else
sched_setaffinity(0, sizeof(process_mask), &process_mask);
#endif
#else
if (process_mask != system_mask)
SetProcessAffinityMask(process, process_mask);
#endif
}
#endif
if (old_block_count == block_count_)
ProcessCPU(method);
}
void HardwareID::ProcessCPU(uint8_t method)
{
int info[4];
__cpuid(info, 1);
if ((info[0] & 0xFF0) == 0xFE0)
info[0] ^= 0x20; // fix Athlon bug
info[1] &= 0x00FFFFFF; // mask out APIC Physical ID
if (method == 2) {
info[2] = 0;
} else if (method == 1) {
info[2] &= ~(1 << 27);
}
AddBlock(info, sizeof(info), BLOCK_CPU);
}
void HardwareID::GetMachineName()
{
#ifdef __APPLE__
CFStringRef computer_name = SCDynamicStoreCopyComputerName(NULL, NULL);
if (!computer_name)
return;
CFIndex len = CFStringGetLength(computer_name);
CFIndex size = CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8);
char *buf = new char[size];
if (CFStringGetCString(computer_name, buf, size, kCFStringEncodingUTF8))
AddBlock(buf, strlen(buf), BLOCK_HOST);
delete [] buf;
CFRelease(computer_name);
#elif defined(__unix__)
char buf[HOST_NAME_MAX+1] = {0};
if (0 == gethostname(buf, HOST_NAME_MAX))
AddBlock(buf, strlen(buf), BLOCK_HOST);
#elif defined(WIN_DRIVER)
#define MAX_COMPUTERNAME_LENGTH 31
wchar_t buf[MAX_COMPUTERNAME_LENGTH + 1];
size_t size = _countof(buf);
if (GetRegValue(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ComputerName", L"ComputerName", buf, &size) ||
GetRegValue(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName", L"ComputerName", buf, &size)) {
AddBlock(buf, size * sizeof(wchar_t), BLOCK_HOST);
}
#else
HMODULE dll = LoadLibraryA(VMProtectDecryptStringA("kernel32.dll"));
if (!dll)
return;
typedef ULONG (WINAPI *GET_COMPUTER_NAME) (wchar_t *, uint32_t *);
GET_COMPUTER_NAME get_computer_name = reinterpret_cast<GET_COMPUTER_NAME>(InternalGetProcAddress(dll, VMProtectDecryptStringA("GetComputerNameW")));
if (get_computer_name) {
wchar_t buf[MAX_COMPUTERNAME_LENGTH + 1];
uint32_t size = _countof(buf);
if (get_computer_name(buf, &size))
AddBlock(buf, size * sizeof(wchar_t), BLOCK_HOST);
}
FreeLibrary(dll);
#endif
}
void HardwareID::ProcessMAC(const uint8_t *p, size_t size)
{
// this big IF construction allows to put constants to the code, not to the data segment
// it is harder to find them in the code after virtualisation
uint32_t dw = (p[0] << 16) + (p[1] << 8) + p[2];
if (dw == 0x000569 || dw == 0x000C29 || dw == 0x001C14 || dw == 0x005056 || // vmware
dw == 0x0003FF || dw == 0x000D3A || dw == 0x00125A || dw == 0x00155D || dw == 0x0017FA || dw == 0x001DD8 || dw == 0x002248 || dw == 0x0025AE || dw == 0x0050F2 || // microsoft
dw == 0x001C42 || // parallels
dw == 0x0021F6) // virtual iron
return;
AddBlock(p, size, BLOCK_MAC);
}
void HardwareID::GetMacAddresses()
{
#ifdef __APPLE__
ifaddrs *addrs;
if (getifaddrs(&addrs) == 0) {
uint32_t block_count_no_mac = block_count_;
const uint8_t *mac = NULL;
size_t size = 0;
for (ifaddrs *cur_addr = addrs; cur_addr != 0; cur_addr = cur_addr->ifa_next) {
if (cur_addr->ifa_addr->sa_family != AF_LINK)
continue;
const sockaddr_dl *dl_addr = reinterpret_cast<const sockaddr_dl *>(cur_addr->ifa_addr);
if (dl_addr->sdl_type == IFT_ETHER) {
mac = reinterpret_cast<const uint8_t *>(&dl_addr->sdl_data[dl_addr->sdl_nlen]);
size = dl_addr->sdl_alen;
ProcessMAC(mac, size);
}
}
if (block_count_no_mac == block_count_ && mac && size)
AddBlock(mac, size, BLOCK_MAC);
freeifaddrs(addrs);
}
#elif defined(__unix__)
std::string dir_name("/sys/class/net/");
if (DIR *dir = opendir(dir_name.c_str())) {
uint32_t block_count_no_mac = block_count_;
uint8_t mac[6];
size_t size = 0;
while (struct dirent *entry = readdir(dir)) {
// skip "." and ".."
if (entry->d_name[0] == '.') {
if (entry->d_name[1] == 0 || (entry->d_name[1] == '.' && entry->d_name[2] == 0))
continue;
}
struct stat st;
if (fstatat(dirfd(dir), entry->d_name, &st, 0) >= 0 && S_ISDIR(st.st_mode)) {
std::string file_name = dir_name + entry->d_name + "/address";
if (FILE *faddr = fopen(file_name.c_str(), "r")) {
char addr[18] = {0};
if (fgets(addr, sizeof(addr) - 1, faddr)) {
uint8_t m[6];
size_t c = sscanf_s(addr, "%02hx:%02hx:%02hx:%02hx:%02hx:%02hx",
m+0, m+1, m+2, m+3, m+4, m+5);
if (c == 6 && m[0]+m[1]+m[2]+m[3]+m[4]+m[5] != 0) {
memcpy(mac, m, sizeof(mac));
size = c;
ProcessMAC(mac, size);
}
}
fclose(faddr);
}
}
}
closedir(dir);
if (block_count_no_mac == block_count_ && size)
AddBlock(mac, size, BLOCK_MAC);
}
#elif defined(WIN_DRIVER)
UNICODE_STRING unicode_string;
OBJECT_ATTRIBUTES object_attributes;
NTSTATUS status;
HANDLE key_handle, file_handle, event_handle;
IO_STATUS_BLOCK status_block;
ULONG code = OID_802_3_CURRENT_ADDRESS;
uint8_t mac[6];
size_t size = 0;
InitializeObjectAttributes(&object_attributes, NULL, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwCreateEvent(&event_handle, EVENT_ALL_ACCESS, &object_attributes, NotificationEvent, FALSE);
if (!NT_SUCCESS(status))
return;
RtlInitUnicodeString(&unicode_string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters");
InitializeObjectAttributes(&object_attributes, &unicode_string, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwOpenKey(&key_handle, GENERIC_READ, &object_attributes);
if (NT_SUCCESS(status)) {
uint32_t block_count_no_mac = block_count_;
ULONG sub_key_size = sizeof(KEY_BASIC_INFORMATION) + sizeof(wchar_t) * MAX_PATH;
KEY_BASIC_INFORMATION *sub_key_value = static_cast<KEY_BASIC_INFORMATION *>(ExAllocatePool(PagedPool, sub_key_size));
wchar_t *service_name = static_cast<wchar_t *>(ExAllocatePool(PagedPool, sizeof(wchar_t) * MAX_PATH));
ULONG ret_size;
for (ULONG i = 0; NT_SUCCESS(ZwEnumerateKey(key_handle, i, KeyBasicInformation, sub_key_value, sub_key_size, &ret_size)); i++) {
if (sub_key_value->NameLength > (MAX_PATH - 10) * sizeof(wchar_t))
continue;
if (sub_key_value->NameLength == 18 && _wcsnicmp(sub_key_value->Name, L"NdisWanIp", 9) == 0)
continue;
RtlZeroMemory(service_name, sizeof(wchar_t) * MAX_PATH);
#if WDK_NTDDI_VERSION > NTDDI_WIN7
wcscat_s(service_name, MAX_PATH, L"\\??\\");
#else
wcscat(service_name, L"\\??\\");
#endif
RtlCopyMemory(service_name + wcslen(service_name), sub_key_value->Name, sub_key_value->NameLength);
RtlInitUnicodeString(&unicode_string, service_name);
InitializeObjectAttributes(&object_attributes, &unicode_string, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwOpenFile(&file_handle, 0, &object_attributes, &status_block, FILE_SHARE_READ | FILE_SHARE_WRITE, 0);
if (NT_SUCCESS(status)) {
status = ZwDeviceIoControlFile(file_handle, event_handle, 0, 0, &status_block, IOCTL_NDIS_QUERY_GLOBAL_STATS, &code, sizeof(code), mac, sizeof(mac));
if (status == STATUS_PENDING)
status = ZwWaitForSingleObject(event_handle, FALSE, NULL);
if (NT_SUCCESS(status)) {
size = sizeof(mac);
ProcessMAC(mac, size);
}
ZwClose(file_handle);
}
}
ExFreePool(service_name);
ExFreePool(sub_key_value);
ZwClose(key_handle);
if (block_count_no_mac == block_count_ && size)
AddBlock(mac, size, BLOCK_MAC);
}
ZwClose(event_handle);
#else
HMODULE dll = LoadLibraryA(VMProtectDecryptStringA("iphlpapi.dll"));
if (!dll)
return;
typedef ULONG (WINAPI *GET_ADAPTERS_INFO) (PIP_ADAPTER_INFO AdapterInfo, PULONG SizePointer);
GET_ADAPTERS_INFO get_adapters_info = reinterpret_cast<GET_ADAPTERS_INFO>(InternalGetProcAddress(dll, VMProtectDecryptStringA("GetAdaptersInfo")));
if (get_adapters_info) {
ULONG buf_len = 0;
if (ERROR_BUFFER_OVERFLOW == get_adapters_info(NULL, &buf_len)) {
uint32_t block_count_no_mac = block_count_;
const uint8_t *mac = NULL;
size_t size = 0;
uint8_t *info = new uint8_t[buf_len];
if (ERROR_SUCCESS == get_adapters_info(reinterpret_cast<IP_ADAPTER_INFO *>(info), &buf_len)) {
for (IP_ADAPTER_INFO *adapter_info = reinterpret_cast<IP_ADAPTER_INFO *>(info); adapter_info != 0; adapter_info = adapter_info->Next) {
mac = adapter_info->Address;
size = adapter_info->AddressLength;
ProcessMAC(mac, size);
}
}
if (block_count_no_mac == block_count_ && mac && size)
AddBlock(mac, size, BLOCK_MAC);
delete [] info;
}
}
FreeLibrary(dll);
#endif
}
void HardwareID::GetHDD()
{
#ifdef __APPLE__
DASessionRef session = DASessionCreate(NULL);
if (session) {
struct statfs statFS;
statfs ("/", &statFS);
DADiskRef disk = DADiskCreateFromBSDName(NULL, session, statFS.f_mntfromname);
if (disk) {
CFDictionaryRef descDict = DADiskCopyDescription(disk);
if (descDict) {
CFUUIDRef value = (CFUUIDRef)CFDictionaryGetValue(descDict, CFSTR("DAVolumeUUID"));
CFUUIDBytes bytes = CFUUIDGetUUIDBytes(value);
AddBlock(&bytes, sizeof(bytes), BLOCK_HDD);
CFRelease(descDict);
}
CFRelease(disk);
}
CFRelease(session);
}
#elif defined(__unix__)
std::string root_uuid;
if (FILE *mtab = setmntent("/etc/mtab", "r")) {
std::string root_fs_path;
while (struct mntent *entry = getmntent(mtab)) {
if (entry->mnt_dir[0] == '/' && entry->mnt_dir[1] == 0) {
root_fs_path = entry->mnt_fsname;
break;
}
}
endmntent(mtab);
if (!root_fs_path.empty()) {
std::string dir_name("/dev/disk/by-uuid/");
if (DIR *dir = opendir(dir_name.c_str())) {
while (struct dirent *entry = readdir(dir)) {
// skip "." and ".."
if (entry->d_name[0] == '.') {
if (entry->d_name[1] == 0 || (entry->d_name[1] == '.' && entry->d_name[2] == 0))
continue;
}
char resolved_link_path[PATH_MAX];
std::string path = dir_name + entry->d_name;
if (realpath(path.c_str(), resolved_link_path)) {
if (strcmp(resolved_link_path, root_fs_path.c_str()) == 0) {
root_uuid = entry->d_name;
break;
}
}
}
closedir(dir);
}
}
}
if (!root_uuid.empty())
AddBlock(root_uuid.c_str(), root_uuid.size(), BLOCK_HDD);
#elif defined(WIN_DRIVER)
wchar_t buf[MAX_PATH];
size_t size = _countof(buf);
UNICODE_STRING unicode_string;
OBJECT_ATTRIBUTES object_attributes;
NTSTATUS status;
HANDLE handle;
IO_STATUS_BLOCK status_block;
if (!GetRegValue(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion", L"SystemRoot", buf, &size))
return;
if (buf[1] == ':' && buf[2] == '\\') {
wchar_t system_drive[] = {'\\', 'D', 'o', 's', 'D', 'e', 'v', 'i', 'c', 'e', 's', '\\', buf[0], ':', '\\', 0};
RtlInitUnicodeString(&unicode_string, system_drive);
InitializeObjectAttributes(&object_attributes, &unicode_string, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateFile(&handle, SYNCHRONIZE | FILE_READ_ACCESS,
&object_attributes,
&status_block,
NULL,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (NT_SUCCESS(status)) {
RtlInitUnicodeString(&unicode_string, L"ZwQueryVolumeInformationFile");
typedef NTSTATUS (NTAPI *QUERY_VOLUME_INFORMATION_FILE) (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS);
QUERY_VOLUME_INFORMATION_FILE query_volume_information_file = reinterpret_cast<QUERY_VOLUME_INFORMATION_FILE>(MmGetSystemRoutineAddress(&unicode_string));
if (query_volume_information_file) {
ULONG size = sizeof(FILE_FS_VOLUME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
FILE_FS_VOLUME_INFORMATION *information = reinterpret_cast<FILE_FS_VOLUME_INFORMATION*>(new uint8_t[size]);
status = query_volume_information_file(handle, &status_block, information, size, FileFsVolumeInformation);
if (NT_SUCCESS(status))
AddBlock(&information->VolumeSerialNumber, sizeof(information->VolumeSerialNumber), BLOCK_HDD);
delete [] information;
}
ZwClose(handle);
}
}
#else
HMODULE dll = LoadLibraryA(VMProtectDecryptStringA("kernel32.dll"));
if (!dll)
return;
typedef ULONG (WINAPI *GET_WINDOWS_DIRECTORY) (wchar_t *, DWORD);
GET_WINDOWS_DIRECTORY get_windows_directory = reinterpret_cast<GET_WINDOWS_DIRECTORY>(InternalGetProcAddress(dll, VMProtectDecryptStringA("GetWindowsDirectoryW")));
typedef BOOL (WINAPI *GET_VOLUME_INFORMATION) (const wchar_t *, wchar_t *, DWORD, DWORD *, DWORD *, DWORD *, wchar_t *, DWORD);
GET_VOLUME_INFORMATION get_volume_information = reinterpret_cast<GET_VOLUME_INFORMATION>(InternalGetProcAddress(dll, VMProtectDecryptStringA("GetVolumeInformationW")));
if (get_windows_directory && get_volume_information) {
wchar_t buf[MAX_PATH] = {0};
UINT ures = get_windows_directory(buf, _countof(buf));
if (ures > 0 && buf[1] == ':' && buf[2] == '\\') {
buf[3] = 0;
DWORD volumeSerialNumber = 0;
if (get_volume_information(buf, NULL, 0, &volumeSerialNumber, NULL, NULL, NULL, 0)) {
AddBlock(&volumeSerialNumber, sizeof(volumeSerialNumber), BLOCK_HDD);
}
}
}
FreeLibrary(dll);
#endif
}
size_t HardwareID::Copy(void *dest, size_t size) const
{
uint32_t *p = reinterpret_cast<uint32_t *>(dest);
// need skip old methods
size_t res = std::min(static_cast<size_t>(block_count_ - start_block_), size / sizeof(uint32_t));
for (size_t i = 0; i < res; i++) {
p[i] = blocks_->GetDWord((start_block_ + i) * sizeof(uint32_t));
}
return res * sizeof(uint32_t);
}
/*
Rules:
1. if pointer to buffer is NULL, second parameter is ignored and returned size of buffer that will fit HWID (with trailing 0)
2. if buffer is ok and the second parameters is zero, we should return zero and doesn't change the buffer
3. if buffer is OK and the second parameter is less than we need, we should return as much bytes as we can and return the second parameter itself
and we should put 0 to the last available position at buffer
4. if buffer is bigger that we need, we should put HWID, trailing 0 and return strlen(hwid) + 1
*/
int HardwareID::GetCurrent(char *buffer, int size)
{
if (buffer && size == 0)
return 0; // see rule #2
uint8_t b[MAX_BLOCKS *sizeof(uint32_t)];
size_t hwid_size = Copy(b, sizeof(b));
size_t need_size = Base64EncodeGetRequiredLength(hwid_size);
char *p = new char[need_size + 1];
Base64Encode(b, hwid_size, p, need_size); // it never should return false
size_t copy = 0;
if (buffer) {
// if nSize is less, we have to leave space for trailing zero (see rule #3)
// if nNeedSize is less, we already have this space, as we allocated nNeedSize + 1 bytes
copy = std::min(static_cast<size_t>(size - 1), need_size);
for (size_t i = 0; i < copy; i++) {
buffer[i] = p[i];
}
buffer[copy++] = 0;
}
else {
// see rule #1
copy = need_size + 1;
}
delete [] p;
return static_cast<int>(copy);
}
bool HardwareID::IsCorrect(uint8_t *p, size_t size) const
{
if (p == 0 || size == 0 || (size & 3))
return false;
bool equals[4];
bool found[4];
for (size_t i = 0; i < 4; i++) {
equals[i] = false;
found[i] = false;
}
size_t blocks = size / sizeof(uint32_t);
uint32_t *d = reinterpret_cast<uint32_t *>(p);
for (size_t j = 0; j < block_count_; j++) {
uint32_t id1 = blocks_->GetDWord(j * sizeof(uint32_t));
found[id1 & 3] = true;
for (size_t i = 0; i < blocks; i++) {
uint32_t id2 = d[i];
if (id1 == id2) {
equals[id1 & 3] = true;
break;
}
}
}
// check CPU
if (!equals[0])
return false;
// check if at least 3 items are OK
size_t n = 0;
size_t c = 0;
for (size_t i = 0; i < 4; i++) {
if (found[i])
c++;
if (equals[i])
n++;
}
return (n == c || n >= 3);
}
bool HardwareID::IsCorrect(CryptoContainer &cont, size_t offset, size_t size) const
{
if (size == 0 || (size & 3) || size > MAX_BLOCKS * sizeof(uint32_t))
return false;
uint32_t buff[MAX_BLOCKS];
for (size_t i = 0; i < size / sizeof(uint32_t); i++) {
buff[i] = cont.GetDWord(offset + i * sizeof(uint32_t));
}
return IsCorrect(reinterpret_cast<uint8_t *>(buff), size);
}