#include "common.h" #include "objects.h" #include "utils.h" #include "hwid.h" #include "core.h" #include "crypto.h" #ifdef __unix__ #include #include #include #include #endif #ifdef VMP_GNU EXPORT_API int WINAPI ExportedGetCurrentHWID(char *buffer, int size) __asm__ ("ExportedGetCurrentHWID"); #endif #ifdef WIN_DRIVER #include 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(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(×tamp)); // 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(p), size); uint32_t block = __builtin_bswap32(*reinterpret_cast(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(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(cur_addr->ifa_addr); if (dl_addr->sdl_type == IFT_ETHER) { mac = reinterpret_cast(&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(ExAllocatePool(PagedPool, sub_key_size)); wchar_t *service_name = static_cast(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(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(info), &buf_len)) { for (IP_ADAPTER_INFO *adapter_info = reinterpret_cast(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(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(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(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(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(dest); // need skip old methods size_t res = std::min(static_cast(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 - 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(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(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(buff), size); }