Skip to content

Commit d8f6602

Browse files
author
Requiem
committed
Improved debug analysis
1 parent 4f816fe commit d8f6602

2 files changed

Lines changed: 69 additions & 49 deletions

File tree

docs/documentation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ VMAware provides a convenient way to not only check for VMs, but also have the f
404404
| `VM::CPU_BRAND` | Check if CPU brand model contains any VM-specific string snippets | | 50% | | | | | |
405405
| `VM::HYPERVISOR_BIT` | Check if hypervisor feature bit in CPUID eax bit 31 is enabled (always false for physical CPUs) | | 100% | | | | |
406406
| `VM::HYPERVISOR_STR` | Check for hypervisor brand string length (would be around 2 characters in a host machine) | | 75% | | | | |
407-
| `VM::TIMER` | Check for timing anomalies in the system | | 20% | | | | | |
407+
| `VM::TIMER` | Check for timing anomalies in the system | | 45% | | | | | |
408408
| `VM::THREADCOUNT` | Check if there are only 1 or 2 threads, which is a common pattern in VMs with default settings (nowadays physical CPUs should have at least 4 threads for modern CPUs) | | 35% | | | | |
409409
| `VM::MAC` | Check if mac address starts with certain VM designated values | Linux and Windows | 20% | | | | |
410410
| `VM::TEMPERATURE` | Check if thermal directory in linux is present, might not be present in VMs | Linux | 15% | | | |

src/vmaware.hpp

Lines changed: 68 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3052,6 +3052,7 @@ struct VM {
30523052

30533053
for (const auto& check : dll_checks) {
30543054
if (GetModuleHandleA(check.dll_name) != nullptr) {
3055+
debug("DLL: Found ", check.dll_name, " (", check.brand, ")");
30553056
return core::add(check.brand);
30563057
}
30573058
}
@@ -3272,7 +3273,7 @@ struct VM {
32723273
wow64RedirectDisabled = true;
32733274
}
32743275

3275-
// Use the system directory instead of the Windows directory.
3276+
// System directory instead of the Windows directory
32763277
char szSysDir[MAX_PATH] = { 0 };
32773278
if (GetSystemDirectoryA(szSysDir, MAX_PATH) == 0) {
32783279
if (wow64RedirectDisabled) {
@@ -3281,23 +3282,26 @@ struct VM {
32813282
return false;
32823283
}
32833284

3284-
constexpr std::array<const char*, 29> vbox_and_vmware = { {
3285-
"drivers\\Vmmouse.sys",
3286-
"drivers\\Vmusbmouse.sys",
3287-
"drivers\\vm3dgl.dll",
3288-
"drivers\\vmdum.dll",
3289-
"drivers\\VmGuestLibJava.dll",
3290-
"drivers\\vm3dver.dll",
3291-
"drivers\\vmtray.dll",
3292-
"drivers\\VMToolsHook.dll",
3293-
"drivers\\vmGuestLib.dll",
3294-
"drivers\\vmhgfs.dll",
3285+
constexpr std::array<const char*, 12> vmwareFiles = { {
3286+
"drivers\\Vmmouse.sys",
3287+
"drivers\\Vmusbmouse.sys",
3288+
"drivers\\vm3dgl.dll",
3289+
"drivers\\vmdum.dll",
3290+
"drivers\\VmGuestLibJava.dll",
3291+
"drivers\\vm3dver.dll",
3292+
"drivers\\vmtray.dll",
3293+
"drivers\\VMToolsHook.dll",
3294+
"drivers\\vmGuestLib.dll",
3295+
"drivers\\vmhgfs.dll",
3296+
"vm3dum64_loader.dll",
3297+
"vm3dum64_10.dll"
3298+
} };
3299+
3300+
constexpr std::array<const char*, 17> vboxFiles = { {
32953301
"drivers\\VBoxMouse.sys",
32963302
"drivers\\VBoxGuest.sys",
32973303
"drivers\\VBoxSF.sys",
32983304
"drivers\\VBoxVideo.sys",
3299-
"vm3dum64_loader.dll",
3300-
"vm3dum64_10.dll",
33013305
"vboxoglpackspu.dll",
33023306
"vboxoglpassthroughspu.dll",
33033307
"vboxservice.exe",
@@ -3341,25 +3345,21 @@ struct VM {
33413345
"drivers\\vpc-s3.sys"
33423346
} };
33433347

3344-
u8 vbox = 0, vmware = 0, kvm = 0, vpc = 0, parallels = 0;
3345-
3346-
auto file_exists = [](const char* path) -> bool {
3347-
DWORD attrs = GetFileAttributesA(path);
3348-
return (attrs != INVALID_FILE_ATTRIBUTES) && !(attrs & FILE_ATTRIBUTE_DIRECTORY);
3349-
};
3348+
u8 vmware = 0, vbox = 0, kvm = 0, vpc = 0, parallels = 0;
33503349

33513350
auto checkFiles = [&](const auto& files, u8& count) {
33523351
for (const auto& relativePath : files) {
33533352
char szPath[MAX_PATH] = { 0 };
3354-
// system directory + relative path, so for example: C:\Windows\System32\ + drivers\VBoxMouse.sys
3353+
// Combination of the system directory with the relative path
33553354
PathCombineA(szPath, szSysDir, relativePath);
3356-
if (file_exists(szPath)) {
3355+
if (util::exists(szPath)) {
33573356
count++;
33583357
}
33593358
}
33603359
};
33613360

3362-
checkFiles(vbox_and_vmware, vbox);
3361+
checkFiles(vmwareFiles, vmware);
3362+
checkFiles(vboxFiles, vbox);
33633363
checkFiles(kvmFiles, kvm);
33643364
checkFiles(parallelsFiles, parallels);
33653365
checkFiles(vpcFiles, vpc);
@@ -3368,28 +3368,30 @@ struct VM {
33683368
Wow64RevertWow64FsRedirection(&oldValue);
33693369
}
33703370

3371-
if (file_exists("C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\StartUp\\agent.pyw")) {
3371+
if (util::exists("C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\StartUp\\agent.pyw")) {
3372+
debug("VM Files: Found startup agent (agent.pyw), indicating CUCKOO VM.");
33723373
return core::add(brands::CUCKOO);
33733374
}
3374-
33753375
if (vbox > vmware && vbox > kvm && vbox > vpc && vbox > parallels) {
3376+
debug("VM Files: Detected VBox files with count ", vbox);
33763377
return core::add(brands::VBOX);
33773378
}
33783379
if (vmware > vbox && vmware > kvm && vmware > vpc && vmware > parallels) {
3380+
debug("VM Files: Detected VMware files with count ", vmware);
33793381
return core::add(brands::VMWARE);
33803382
}
33813383
if (kvm > vbox && kvm > vmware && kvm > vpc && kvm > parallels) {
3384+
debug("VM Files: Detected KVM files with count ", kvm);
33823385
return core::add(brands::KVM);
33833386
}
33843387
if (vpc > vbox && vpc > vmware && vpc > kvm && vpc > parallels) {
3388+
debug("VM Files: Detected VPC files with count ", vpc);
33853389
return core::add(brands::VPC);
33863390
}
33873391
if (parallels > vbox && parallels > vmware && parallels > kvm && parallels > vpc) {
3392+
debug("VM Files: Detected Parallels files with count ", parallels);
33883393
return core::add(brands::PARALLELS);
33893394
}
3390-
if (vbox > 0 && vmware > 0 && kvm > 0 && vpc > 0 && parallels > 0) {
3391-
return true;
3392-
}
33933395

33943396
return false;
33953397
#endif
@@ -3808,39 +3810,50 @@ struct VM {
38083810
* @implements VM::VM_PROCESSES
38093811
*/
38103812
[[nodiscard]] static bool vm_processes() {
3811-
#if (!WINDOWS)
3813+
#if (!WINDOWS)
38123814
return false;
3813-
#else
3814-
if (util::is_proc_running(("joeboxserver.exe")) || util::is_proc_running(("joeboxcontrol.exe"))) {
3815+
#else
3816+
if (util::is_proc_running("joeboxserver.exe") || util::is_proc_running("joeboxcontrol.exe")) {
3817+
debug("VM_PROCESSES: Detected JoeBox process.");
38153818
return core::add(brands::JOEBOX);
38163819
}
38173820

3818-
if (util::is_proc_running(("prl_cc.exe")) || util::is_proc_running(("prl_tools.exe"))) {
3821+
if (util::is_proc_running("prl_cc.exe") || util::is_proc_running("prl_tools.exe")) {
3822+
debug("VM_PROCESSES: Detected Parallels process.");
38193823
return core::add(brands::PARALLELS);
38203824
}
38213825

3822-
if (util::is_proc_running(("vboxservice.exe")) || util::is_proc_running(("vboxtray.exe"))) {
3826+
if (util::is_proc_running("vboxservice.exe") || util::is_proc_running("vboxtray.exe")) {
3827+
debug("VM_PROCESSES: Detected VBox process.");
38233828
return core::add(brands::VBOX);
38243829
}
38253830

3826-
if (util::is_proc_running(("vmsrvc.exe")) || util::is_proc_running(("vmusrvc.exe"))) {
3831+
if (util::is_proc_running("vmsrvc.exe") || util::is_proc_running("vmusrvc.exe")) {
3832+
debug("VM_PROCESSES: Detected VPC process.");
38273833
return core::add(brands::VPC);
38283834
}
38293835

3830-
if (util::is_proc_running(("xenservice.exe")) || util::is_proc_running(("xsvc_depriv.exe"))) {
3836+
if (util::is_proc_running("xenservice.exe") || util::is_proc_running("xsvc_depriv.exe")) {
3837+
debug("VM_PROCESSES: Detected Xen process.");
38313838
return core::add(brands::XEN);
38323839
}
38333840

3834-
if (util::is_proc_running(("vm3dservice.exe")) || util::is_proc_running(("VGAuthService.exe")) || util::is_proc_running(("vmtoolsd.exe"))) {
3841+
if (util::is_proc_running("vm3dservice.exe") ||
3842+
util::is_proc_running("VGAuthService.exe") ||
3843+
util::is_proc_running("vmtoolsd.exe")) {
3844+
debug("VM_PROCESSES: Detected VMware process.");
38353845
return core::add(brands::VMWARE);
38363846
}
38373847

3838-
if (util::is_proc_running(("vdagent.exe")) || util::is_proc_running(("vdservice.exe")) || util::is_proc_running(("qemuwmi.exe"))) {
3848+
if (util::is_proc_running("vdagent.exe") ||
3849+
util::is_proc_running("vdservice.exe") ||
3850+
util::is_proc_running("qemuwmi.exe")) {
3851+
debug("VM_PROCESSES: Detected QEMU process.");
38393852
return core::add(brands::QEMU);
38403853
}
38413854

38423855
return false;
3843-
#endif
3856+
#endif
38443857
}
38453858

38463859

@@ -4385,6 +4398,7 @@ struct VM {
43854398
if (dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ) {
43864399
buffer[bufferSize - 1] = '\0';
43874400
if (strstr(buffer, comp_string) != nullptr) {
4401+
debug("HKLM_REGISTRIES: Found ", comp_string, " in ", subKey, " for brand ", p_brand);
43884402
core::add(p_brand);
43894403
count++;
43904404
}
@@ -6595,20 +6609,20 @@ struct VM {
65956609
}
65966610

65976611
if (lowestReservedAddrRangeEnd != lowestLoaderReservedAddrRangeEnd) {
6598-
return false; // No VM detected
6612+
return false;
65996613
}
66006614

6601-
/* Now check for Hyper-V or VirtualBox by memory ranges */
6615+
/* Hyper-V and VirtualBox by memory ranges */
66026616
for (DWORD i = 0; i < phys_count; i++) {
66036617
if (phys[i].address == HYPERV_PHYS_LO && (phys[i].address + phys[i].size) == HYPERV_PHYS_HI) {
6604-
return true; // Detected Hyper-V
6618+
return core::add(VM::brands::HYPERV);
66056619
}
66066620
if (phys[i].address == VBOX_PHYS_LO && (phys[i].address + phys[i].size) == VBOX_PHYS_HI) {
6607-
return true; // Detected VirtualBox
6621+
return core::add(VM::brands::VBOX);
66086622
}
66096623
}
66106624

6611-
return false; // Possibly VM, but unable to identify platform
6625+
return false;
66126626
#endif
66136627
}
66146628

@@ -7463,7 +7477,6 @@ struct VM {
74637477
#if (!WINDOWS)
74647478
return false;
74657479
#else
7466-
74677480
typedef struct _SYSTEM_MODULE_INFORMATION {
74687481
PVOID Reserved[2];
74697482
PVOID ImageBaseAddress;
@@ -7545,6 +7558,8 @@ struct VM {
75457558
strstr(driverPath, "VBoxMouse") ||
75467559
strstr(driverPath, "VBoxSF")
75477560
) {
7561+
debug("DRIVER_NAMES: Detected VBox driver: ", driverPath);
7562+
ntFreeVirtualMemory(hProcess, &allocatedMemory, &regionSize, MEM_RELEASE);
75487563
return core::add(brands::VBOX);
75497564
}
75507565

@@ -7553,6 +7568,8 @@ struct VM {
75537568
strstr(driverPath, "vmmouse") ||
75547569
strstr(driverPath, "vmmemctl")
75557570
) {
7571+
debug("DRIVER_NAMES: Detected VMware driver: ", driverPath);
7572+
ntFreeVirtualMemory(hProcess, &allocatedMemory, &regionSize, MEM_RELEASE);
75567573
return core::add(brands::VMWARE);
75577574
}
75587575
}
@@ -7889,15 +7906,18 @@ struct VM {
78897906
CloseHandle(handle4);
78907907

78917908
if (result) {
7909+
debug("VM_DEVICES: Detected VBox related device handles.");
78927910
return core::add(brands::VBOX);
78937911
}
78947912

78957913
if (handle5 != INVALID_HANDLE_VALUE) {
78967914
CloseHandle(handle5);
7915+
debug("VM_DEVICES: Detected VMware related device (HGFS).");
78977916
return core::add(brands::VMWARE);
78987917
}
78997918
if (handle6 != INVALID_HANDLE_VALUE) {
79007919
CloseHandle(handle6);
7920+
debug("VM_DEVICES: Detected Cuckoo related device (pipe).");
79017921
return core::add(brands::CUCKOO);
79027922
}
79037923

@@ -8470,7 +8490,7 @@ struct VM {
84708490
QueryPerformanceCounter(&endQPC);
84718491
LONGLONG dummyTime = endQPC.QuadPart - startQPC.QuadPart;
84728492

8473-
const bool qpc_check = (dummyTime != 0) && ((cpuIdTime / dummyTime) > 1100);
8493+
const bool qpc_check = (dummyTime != 0) && ((cpuIdTime / dummyTime) > 1500);
84748494
debug("QPC check - CPUID: ", cpuIdTime, "ns, Dummy: ", dummyTime, "ns, Ratio: ", (cpuIdTime / dummyTime));
84758495

84768496
// TSC sync check across cores. Try reading the invariant TSC on two different cores to attempt to detect vCPU timers being shared
@@ -8674,7 +8694,6 @@ struct VM {
86748694
if (pNtQuerySystemInformation) {
86758695
SYSTEM_HYPERVISOR_DETAIL_INFORMATION hvInfo = { {} };
86768696
const NTSTATUS status = pNtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(0x9F), &hvInfo, sizeof(hvInfo), nullptr);
8677-
86788697
if (status != 0) {
86798698
return false;
86808699
}
@@ -8975,6 +8994,7 @@ struct VM {
89758994

89768995
for (size_t j = 0; j < badPoolCount; ++j) {
89778996
if (currentTag == BadPoolDwords[j]) {
8997+
debug("Bad Pools: Detected bad pool tag: 0x", std::hex, currentTag, std::dec);
89788998
++bad_pool_number;
89798999
break;
89809000
}
@@ -9814,7 +9834,6 @@ struct VM {
98149834
if (!ntqsi)
98159835
return false;
98169836

9817-
// List of target strings (all are now treated as valid hits)
98189837
constexpr const char* targets[] = {
98199838
"Parallels Software International", "Parallels(R)", "innotek",
98209839
"Oracle", "VirtualBox", "VS2005R2", "VMware, Inc.",
@@ -10068,6 +10087,7 @@ struct VM {
1006810087
}
1006910088
}
1007010089

10090+
debug("UNKNOWN_MANUFACTURER: CPU brand '", brand, "' did not match known vendor IDs.");
1007110091
return true; // no known manufacturer matched, likely a VM
1007210092
}
1007310093

@@ -11668,7 +11688,7 @@ std::pair<VM::enum_flags, VM::core::technique> VM::core::technique_list[] = {
1166811688
{ VM::CPU_BRAND, { 50, VM::cpu_brand } },
1166911689
{ VM::HYPERVISOR_BIT, { 100, VM::hypervisor_bit}} ,
1167011690
{ VM::HYPERVISOR_STR, { 75, VM::hypervisor_str } },
11671-
{ VM::TIMER, { 20, VM::timer } },
11691+
{ VM::TIMER, { 45, VM::timer } },
1167211692
{ VM::THREADCOUNT, { 35, VM::thread_count } },
1167311693
{ VM::MAC, { 20, VM::mac_address_check } },
1167411694
{ VM::TEMPERATURE, { 15, VM::temperature } },

0 commit comments

Comments
 (0)