aboutsummaryrefslogtreecommitdiff
path: root/runtime/hwid.cc
diff options
context:
space:
mode:
authorjmpoep <OriginalEntryPoint@qq.com>2023-12-07 16:51:07 +0800
committerjmpoep <OriginalEntryPoint@qq.com>2023-12-07 16:51:07 +0800
commit28008a746a31abb7909dd86cb0cd413ac8943b0b (patch)
treea30b74b8cad548048c3c1551d652828ab76fa9bd /runtime/hwid.cc
downloadvmprotect-3.5.1-master.tar
vmprotect-3.5.1-master.tar.gz
vmprotect-3.5.1-master.tar.bz2
vmprotect-3.5.1-master.zip
first commitHEADmaster
Diffstat (limited to 'runtime/hwid.cc')
-rw-r--r--runtime/hwid.cc688
1 files changed, 688 insertions, 0 deletions
diff --git a/runtime/hwid.cc b/runtime/hwid.cc
new file mode 100644
index 0000000..e7d1bac
--- /dev/null
+++ b/runtime/hwid.cc
@@ -0,0 +1,688 @@
+#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);
+} \ No newline at end of file