From 99bf3347a20f5f63f78034e1185736e6646eb49d Mon Sep 17 00:00:00 2001 From: kernel <77142078+kernelwernel@users.noreply.github.com> Date: Sun, 11 Aug 2024 23:23:55 +0100 Subject: [PATCH 1/5] preliminary changes --- README.md | 8 +- auxiliary/vmtest.cpp | 16 +- src/cli.cpp | 2 +- src/vmaware.hpp | 628 +++++++++++++++++++++++++------------------ 4 files changed, 386 insertions(+), 268 deletions(-) diff --git a/README.md b/README.md index b6941226..e48015ab 100644 --- a/README.md +++ b/README.md @@ -35,13 +35,13 @@ The library is: int main() { if (VM::detect()) { - std::cout << "Virtual machine detected!" << std::endl; - std::cout << "VM name: " << VM::brand() << std::endl; + std::cout << "Virtual machine detected!" << "\n"; + std::cout << "VM name: " << VM::brand() << "\n"; } else { - std::cout << "Running in baremetal" << std::endl; + std::cout << "Running in baremetal" << "\n"; } - std::cout << "VM certainty: " << (int)VM::percentage() << "%" << std::endl; + std::cout << "VM certainty: " << (int)VM::percentage() << "%" << "\n"; } ``` diff --git a/auxiliary/vmtest.cpp b/auxiliary/vmtest.cpp index 0f959e67..3c11d97a 100644 --- a/auxiliary/vmtest.cpp +++ b/auxiliary/vmtest.cpp @@ -24,13 +24,13 @@ #include int main(void) { - const bool test1 = VM::detect(); - const bool test2 = VM::detect(VM::ALL); - const bool test3 = VM::detect(VM::DEFAULT); - const bool test4 = VM::detect(VM::DEFAULT, VM::ALL); - const bool test5 = VM::detect(VM::DEFAULT, VM::DISABLE(VM::RDTSC)); - const bool test6 = VM::detect(VM::DEFAULT, VM::DISABLE(VM::RDTSC), VM::EXTREME); - const bool test7 = VM::detect(VM::NO_MEMO, VM::EXTREME, VM::MULTIPLE, VM::ENABLE_HYPERV_HOST); - const std::string test8 = VM::brand(); + const bool test1 = VM::detect(VM::CPUID_SIGNATURE); + //const bool test2 = VM::detect(VM::ALL); + //const bool test3 = VM::detect(VM::DEFAULT); + //const bool test4 = VM::detect(VM::DEFAULT, VM::ALL); + //const bool test5 = VM::detect(VM::DEFAULT, VM::DISABLE(VM::RDTSC)); + //const bool test6 = VM::detect(VM::DEFAULT, VM::DISABLE(VM::RDTSC), VM::EXTREME); + //const bool test7 = VM::detect(VM::NO_MEMO, VM::EXTREME, VM::MULTIPLE, VM::ENABLE_HYPERV_HOST); + //const std::string test8 = VM::brand(); return 0; } \ No newline at end of file diff --git a/src/cli.cpp b/src/cli.cpp index e19ff562..4b99e29c 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -637,7 +637,7 @@ void general() { if ((brand == "Hyper-V artifact (not an actual VM)") && notes_enabled) { - std::cout << note << "The result means that the CLI has found Hyper-V, but as an artifact instead of an actual VM. This means that although the hardware values in fact match with Hyper-V due to how it's designed by Microsoft, the CLI has determined you are NOT in a Hyper-V VM.\n\n"; + std::cout << note << " The result means that the CLI has found Hyper-V, but as an artifact instead of an actual VM. This means that although the hardware values in fact match with Hyper-V due to how it's designed by Microsoft, the CLI has determined you are NOT in a Hyper-V VM.\n\n"; } else if (notes_enabled) { if (!arg_bitset.test(SPOOFABLE)) { std::cout << tip << "To enable spoofable techniques, run with the \"--spoofable\" argument\n\n"; diff --git a/src/vmaware.hpp b/src/vmaware.hpp index 232466a1..0e6ef26e 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -490,10 +490,14 @@ struct VM { static constexpr const char* VMWARE_GSX = "VMware GSX"; static constexpr const char* VMWARE_WORKSTATION = "VMware Workstation"; static constexpr const char* VMWARE_FUSION = "VMware Fusion"; - static constexpr const char* KVM = "KVM"; static constexpr const char* BHYVE = "bhyve"; + static constexpr const char* KVM = "KVM"; static constexpr const char* QEMU = "QEMU"; + static constexpr const char* QEMU_KVM = "QEMU+KVM"; + static constexpr const char* KVM_HYPERV = "KVM Hyper-V Enlightenment"; + static constexpr const char* QEMU_KVM_HYPERV = "QEMU+KVM Hyper-V Enlightenment"; static constexpr const char* HYPERV = "Microsoft Hyper-V"; + static constexpr const char* HYPERV_VPC = "Microsoft Virtual PC/Hyper-V"; static constexpr const char* MSXTA = "Microsoft x86-to-ARM"; static constexpr const char* PARALLELS = "Parallels"; static constexpr const char* XEN = "Xen HVM"; @@ -511,7 +515,6 @@ struct VM { static constexpr const char* CWSANDBOX = "CWSandbox"; static constexpr const char* COMODO = "Comodo"; static constexpr const char* BOCHS = "Bochs"; - static constexpr const char* KVM_HYPERV = "KVM Hyper-V Enlightenment"; static constexpr const char* NVMM = "NetBSD NVMM"; static constexpr const char* BSD_VMM = "OpenBSD VMM"; static constexpr const char* INTEL_HAXM = "Intel HAXM"; @@ -711,7 +714,7 @@ struct VM { } - [[nodiscard]] static std::string cpu_manufacturer(const u32 p_leaf) { + [[nodiscard]] static std::array cpu_manufacturer(const u32 p_leaf) { auto cpuid_thingy = [](const u32 p_leaf, u32* regs, std::size_t start = 0, std::size_t end = 4) -> bool { u32 x[4]{}; cpu::cpuid(x[0], x[1], x[2], x[3], p_leaf); @@ -721,33 +724,36 @@ struct VM { } return true; - }; + }; - std::string brand = ""; u32 sig_reg[3] = { 0 }; if (!cpuid_thingy(p_leaf, sig_reg, 1)) { - return ""; + return { "", "" }; } auto strconvert = [](u64 n) -> std::string { const std::string& str(reinterpret_cast(&n)); return str; - }; + }; std::stringstream ss; + std::stringstream ss2; ss << strconvert(sig_reg[0]); ss << strconvert(sig_reg[2]); ss << strconvert(sig_reg[1]); + ss2 << strconvert(sig_reg[0]); + ss2 << strconvert(sig_reg[1]); + ss2 << strconvert(sig_reg[2]); + std::string brand_str = ss.str(); + std::string brand_str2 = ss2.str(); - if (brand_str.empty()) { - return ""; - } + const std::array result = { brand_str, brand_str2 }; - return brand_str; + return result; } struct stepping_struct { @@ -883,82 +889,85 @@ struct VM { apple_vz = "Apple VZ", intel_kgt = "EVMMEVMMEVMM"; - const std::string brand_str = cpu_manufacturer(p_leaf); + const std::array brand_strings = cpu_manufacturer(p_leaf); - debug(technique_name, brand_str); + debug(technique_name, brand_strings.at(0)); + debug(technique_name, brand_strings.at(1)); #if (CPP < 17) // bypass compiler warning about unused parameter, ignore this UNUSED(technique_name); #endif - if (brand_str == qemu) { return core::add(QEMU); } - if (brand_str == vmware) { return core::add(VMWARE); } - if (brand_str == vbox) { return core::add(VBOX); } - if (brand_str == bhyve) { return core::add(BHYVE); } - if (brand_str == bhyve2) { return core::add(BHYVE); } - if (brand_str == kvm) { return core::add(KVM); } - if (brand_str == kvm_hyperv) { return core::add(KVM_HYPERV); } - if (brand_str == xta) { return core::add(MSXTA); } - if (brand_str == parallels) { return core::add(PARALLELS); } - if (brand_str == parallels2) { return core::add(PARALLELS); } - if (brand_str == xen) { return core::add(XEN); } - if (brand_str == acrn) { return core::add(ACRN); } - if (brand_str == qnx) { return core::add(QNX); } - if (brand_str == virtapple) { return core::add(VAPPLE); } - if (brand_str == nvmm) { return core::add(NVMM); } - if (brand_str == openbsd_vmm) { return core::add(BSD_VMM); } - if (brand_str == intel_haxm) { return core::add(INTEL_HAXM); } - if (brand_str == unisys) { return core::add(UNISYS); } - if (brand_str == lmhs) { return core::add(LMHS); } - if (brand_str == jailhouse) { return core::add(JAILHOUSE); } - if (brand_str == intel_kgt) { return core::add(INTEL_KGT); } - - // both Hyper-V and VirtualPC have the same string value - if (brand_str == hyperv) { - if (util::hyperv_fucker()) { - return false; + for (const std::string &brand_str : brand_strings) { + if (brand_str == qemu) { return core::add(QEMU); } + if (brand_str == vmware) { return core::add(VMWARE); } + if (brand_str == vbox) { return core::add(VBOX); } + if (brand_str == bhyve) { return core::add(BHYVE); } + if (brand_str == bhyve2) { return core::add(BHYVE); } + if (brand_str == kvm) { return core::add(KVM); } + if (brand_str == kvm_hyperv) { return core::add(KVM_HYPERV); } + if (brand_str == xta) { return core::add(MSXTA); } + if (brand_str == parallels) { return core::add(PARALLELS); } + if (brand_str == parallels2) { return core::add(PARALLELS); } + if (brand_str == xen) { return core::add(XEN); } + if (brand_str == acrn) { return core::add(ACRN); } + if (brand_str == qnx) { return core::add(QNX); } + if (brand_str == virtapple) { return core::add(VAPPLE); } + if (brand_str == nvmm) { return core::add(NVMM); } + if (brand_str == openbsd_vmm) { return core::add(BSD_VMM); } + if (brand_str == intel_haxm) { return core::add(INTEL_HAXM); } + if (brand_str == unisys) { return core::add(UNISYS); } + if (brand_str == lmhs) { return core::add(LMHS); } + if (brand_str == jailhouse) { return core::add(JAILHOUSE); } + if (brand_str == intel_kgt) { return core::add(INTEL_KGT); } + + // both Hyper-V and VirtualPC have the same string value + if (brand_str == hyperv) { + if (util::hyper_x()) { + return false; + } + return core::add(HYPERV, VPC); } - return core::add(HYPERV, VPC); - } - /** - * this is added because there are inconsistent string - * values for KVM's manufacturer ID. For example, - * it gives me "KVMKMVMKV" when I run it under QEMU - * but the Wikipedia article on CPUID says it's - * "KVMKVMKVM\0\0\0", like wtf???? - */ - if (util::find(brand_str, "KVM")) { - return core::add(KVM); - } + /** + * this is added because there are inconsistent string + * values for KVM's manufacturer ID. For example, + * it gives me "KVMKMVMKV" when I run it under QEMU + * but the Wikipedia article on CPUID says it's + * "KVMKVMKVM\0\0\0", like wtf???? + */ + if (util::find(brand_str, "KVM")) { + return core::add(KVM); + } - /** - * i'm honestly not sure about this one, - * they're supposed to have 12 characters but - * Wikipedia tells me it these brands have - * less characters (both 8), so i'm just - * going to scan for the entire string ig - */ + /** + * i'm honestly not sure about this one, + * they're supposed to have 12 characters but + * Wikipedia tells me it these brands have + * less characters (both 8), so i'm just + * going to scan for the entire string ig + */ #if (CPP >= 17) - const char* qnx_sample = qnx2.data(); - const char* applevz_sample = apple_vz.data(); + const char* qnx_sample = qnx2.data(); + const char* applevz_sample = apple_vz.data(); #else - const char* qnx_sample = qnx2.c_str(); - const char* applevz_sample = apple_vz.c_str(); + const char* qnx_sample = qnx2.c_str(); + const char* applevz_sample = apple_vz.c_str(); #endif - if (util::find(brand_str, qnx_sample)) { - return core::add(QNX); - } + if (util::find(brand_str, qnx_sample)) { + return core::add(QNX); + } - if (util::find(brand_str, applevz_sample)) { - return core::add(APPLE); + if (util::find(brand_str, applevz_sample)) { + return core::add(APPLE); + } } return false; } - }; + }; // memoization struct memo { @@ -1202,6 +1211,113 @@ struct VM { } #endif + static std::string flag_to_string(const enum_flags flag) { + switch (flag) { + case VMID: return "VM::VMID"; + case CPU_BRAND: return "VM::CPU_BRAND"; + case HYPERVISOR_BIT: return "VM::HYPERVISOR_BIT"; + case HYPERVISOR_STR: return "VM::HYPERVISOR_STR"; + case RDTSC: return "VM::RDTSC"; + case THREADCOUNT: return "VM::THREADCOUNT"; + case MAC: return "VM::MAC"; + case TEMPERATURE: return "VM::TEMPERATURE"; + case SYSTEMD: return "VM::SYSTEMD"; + case CVENDOR: return "VM::CVENDOR"; + case CTYPE: return "VM::CTYPE"; + case DOCKERENV: return "VM::DOCKERENV"; + case DMIDECODE: return "VM::DMIDECODE"; + case DMESG: return "VM::DMESG"; + case HWMON: return "VM::HWMON"; + case SIDT5: return "VM::SIDT5"; + case CURSOR: return "VM::CURSOR"; + case VMWARE_REG: return "VM::VMWARE_REG"; + case VBOX_REG: return "VM::VBOX_REG"; + case USER: return "VM::USER"; + case DLL: return "VM::DLL"; + case REGISTRY: return "VM::REGISTRY"; + case CWSANDBOX_VM: return "VM::CWSANDBOX_VM"; + case VM_FILES: return "VM::VM_FILES"; + case HWMODEL: return "VM::HWMODEL"; + case DISK_SIZE: return "VM::DISK_SIZE"; + case VBOX_DEFAULT: return "VM::VBOX_DEFAULT"; + case VBOX_NETWORK: return "VM::VBOX_NETWORK"; + case COMPUTER_NAME: return "VM::COMPUTER_NAME"; + case WINE_CHECK: return "VM::WINE_CHECK"; + case HOSTNAME: return "VM::HOSTNAME"; + case MEMORY: return "VM::MEMORY"; + case VBOX_WINDOW_CLASS: return "VM::VBOX_WINDOW_CLASS"; + case LOADED_DLLS: return "VM::LOADED_DLLS"; + case KVM_REG: return "VM::KVM_REG"; + case KVM_DRIVERS: return "VM::KVM_DRIVERS"; + case KVM_DIRS: return "VM::KVM_DIRS"; + case AUDIO: return "VM::AUDIO"; + case QEMU_DIR: return "VM::QEMU_DIR"; + case MOUSE_DEVIC: return "VM::MOUSE_DEVIC"; + case VM_PROCESSES: return "VM::VM_PROCESSES"; + case LINUX_USER_HOST: return "VM::LINUX_USER_HOST"; + case GAMARUE: return "VM::GAMARUE"; + case VMID_0X4: return "VM::VMID_0X4"; + case PARALLELS_VM: return "VM::PARALLELS_VM"; + case RDTSC_VMEXIT: return "VM::RDTSC_VMEXIT"; + case QEMU_BRAND: return "VM::QEMU_BRAND"; + case BOCHS_CPU: return "VM::BOCHS_CPU"; + case VPC_BOARD: return "VM::VPC_BOARD"; + case HYPERV_WMI: return "VM::HYPERV_WMI"; + case HYPERV_REG: return "VM::HYPERV_REG"; + case BIOS_SERIAL: return "VM::BIOS_SERIAL"; + case VBOX_FOLDERS: return "VM::VBOX_FOLDERS"; + case MSSMBIOS: return "VM::MSSMBIOS"; + case MAC_MEMSIZE: return "VM::MAC_MEMSIZE"; + case MAC_IOKIT: return "VM::MAC_IOKIT"; + case IOREG_GREP: return "VM::IOREG_GREP"; + case MAC_SIP: return "VM::MAC_SIP"; + case HKLM_REGISTRIES: return "VM::HKLM_REGISTRIES"; + case QEMU_GA: return "VM::QEMU_GA"; + case VALID_MSR: return "VM::VALID_MSR"; + case QEMU_PROC: return "VM::QEMU_PROC"; + case VPC_PROC: return "VM::VPC_PROC"; + case VPC_INVALID: return "VM::VPC_INVALID"; + case SIDT: return "VM::SIDT"; + case SGDT: return "VM::SGDT"; + case SLDT: return "VM::SLDT"; + case OFFSEC_SIDT: return "VM::OFFSEC_SIDT"; + case OFFSEC_SGDT: return "VM::OFFSEC_SGDT"; + case OFFSEC_SLDT: return "VM::OFFSEC_SLDT"; + case HYPERV_BOARD: return "VM::HYPERV_BOARD"; + case VM_FILES_EXTRA: return "VM::VM_FILES_EXTRA"; + case VPC_SIDT: return "VM::VPC_SIDT"; + case VMWARE_IOMEM: return "VM::VMWARE_IOMEM"; + case VMWARE_IOPORTS: return "VM::VMWARE_IOPORTS"; + case VMWARE_SCSI: return "VM::VMWARE_SCSI"; + case VMWARE_DMESG: return "VM::VMWARE_DMESG"; + case VMWARE_STR: return "VM::VMWARE_STR"; + case VMWARE_BACKDOOR: return "VM::VMWARE_BACKDOOR"; + case VMWARE_PORT_MEM: return "VM::VMWARE_PORT_MEM"; + case SMSW: return "VM::SMSW"; + case MUTEX: return "VM::MUTEX"; + case UPTIME: return "VM::UPTIME"; + case ODD_CPU_THREADS: return "VM::ODD_CPU_THREADS"; + case INTEL_THREAD_MISMATCH: return "VM::INTEL_THREAD_MISMATCH"; + case XEON_THREAD_MISMATCH: return "VM::XEON_THREAD_MISMATCH"; + case NETTITUDE_VM_MEMORY: return "VM::NETTITUDE_VM_MEMORY"; + case CPUID_BITSET: return "VM::CPUID_BITSET"; + case CUCKOO_DIR: return "VM::CUCKOO_DIR"; + case CUCKOO_PIPE: return "VM::CUCKOO_PIPE"; + case HYPERV_HOSTNAME: return "VM::HYPERV_HOSTNAME"; + case GENERAL_HOSTNAME: return "VM::GENERAL_HOSTNAME"; + case SCREEN_RESOLUTION: return "VM::SCREEN_RESOLUTION"; + case DEVICE_STRING: return "VM::DEVICE_STRING"; + case BLUESTACKS_FOLDERS: return "VM::BLUESTACKS_FOLDERS"; + case CPUID_SIGNATURE: return "VM::CPUID_SIGNATURE"; + case HYPERV_BITMASK: return "VM::HYPERV_BITMASK"; + case KVM_BITMASK: return "VM::KVM_BITMASK"; + case KGT_SIGNATURE: return "VM::KGT_SIGNATURE"; + case VMWARE_DMI: return "VM::VMWARE_DMI"; + case EVENT_LOGS: return "VM::EVENT_LOGS"; + default: return "Unknown flag"; + } + } + template static inline void debug_msg(Args... message) noexcept { #if (LINUX || APPLE) @@ -1607,12 +1723,12 @@ struct VM { * @brief Checks whether Hyper-V host artifacts are present instead of an actual Hyper-V VM * @note idea and credits to Requiem (https://github.com/NotRequiem) */ - [[nodiscard]] static bool hyperv_fucker() { + [[nodiscard]] static bool hyper_x() { #if (!MSVC) return false; #else if (memo::hyperv::is_cached()) { - core_debug("HYPERV_FUCKER: returned from cache = ", memo::hyperv::fetch()); + core_debug("HYPER_X: returned from cache = ", memo::hyperv::fetch()); return memo::hyperv::fetch(); } @@ -1631,13 +1747,13 @@ struct VM { const u32 eax = static_cast(out[0]); - core_debug("HYPERV_FUCKER: eax = ", eax); + core_debug("HYPER_X: eax = ", eax); if (eax == 12) { // SMBIOS check const std::string p = SMBIOS_string(); - core_debug("HYPERV_FUCKER: SMBIOS string = ", p); + core_debug("HYPER_X: SMBIOS string = ", p); if (p == "VIRTUAL MACHINE") { return add(false); @@ -1647,7 +1763,7 @@ struct VM { // motherboard check const bool motherboard = motherboard_string(L"Microsoft Corporation"); - core_debug("HYPERV_FUCKER: motherboard string = ", motherboard); + core_debug("HYPER_X: motherboard string = ", motherboard); if (motherboard) { return add(false); @@ -2420,7 +2536,7 @@ struct VM { return false; } - if (util::hyperv_fucker()) { + if (util::hyper_x()) { return false; } @@ -2444,7 +2560,7 @@ struct VM { #if (!x86) return false; #else - if (util::hyperv_fucker()) { + if (util::hyper_x()) { return false; } @@ -5336,16 +5452,20 @@ struct VM { /** * @brief Check for sldt instruction method * @category Windows, x86 + * @note code documentation paper in https://www.aldeid.com/wiki/X86-assembly/Instructions/sldt */ [[nodiscard]] static bool sldt() try { #if (x86_32 && MSVC) - unsigned short ldtr[5] = { 0xEF, 0xBE, 0xAD, 0xDE }; - unsigned int ldt = 0; + unsigned char ldtr[5] = "\xef\xbe\xad\xde"; + unsigned long ldt = 0; - _asm sldt ldtr; - ldt = *((u32*)&ldtr[0]); + __asm { + sldt word ptr ldtr // 'word ptr' to indicate that we're working with a 16-bit value and avoid compiler warnings + } - return (ldt != 0xDEAD0000); + ldt = *((unsigned long*)&ldtr[0]); + + return (ldt != 0xdead0000); #else return false; #endif @@ -5763,20 +5883,18 @@ struct VM { * @note paper describing this technique is located at /papers/www.s21sec.com_vmware-eng.pdf (2006) * @category Windows */ - [[nodiscard]] static bool vmware_str() try { -#if (!MSVC || !x86) - return false; -#elif (x86_32) - unsigned short mem[4] = { 0, 0, 0, 0 }; - - __asm str mem; - - if ((mem[0] == 0x00) && (mem[1] == 0x40)) { + [[nodiscard]] static bool vmware_str() try { +#if (MSVC && x86_32) + unsigned short tr = 0; + __asm { + str ax + mov tr, ax + } + if ((tr & 0xFF) == 0x00 && ((tr >> 8) & 0xFF) == 0x40) { return core::add(VMWARE); } -#else - return false; #endif + return false; } catch (...) { debug("VMWARE_STR: caught error, returned false"); @@ -5835,18 +5953,15 @@ struct VM { if (is_vm) { switch (b) { - case 1: return core::add(VMWARE_EXPRESS); - case 2: return core::add(VMWARE_ESX); - case 3: return core::add(VMWARE_GSX); - case 4: return core::add(VMWARE_WORKSTATION); - default: return core::add(VMWARE); + case 1: return core::add(VMWARE_EXPRESS); + case 2: return core::add(VMWARE_ESX); + case 3: return core::add(VMWARE_GSX); + case 4: return core::add(VMWARE_WORKSTATION); + default: return core::add(VMWARE); } } - - return false; -#else - return false; #endif + return false; } @@ -5915,7 +6030,7 @@ struct VM { return ( (((reax >> 24) & 0xFF) == 0xCC) && (((reax >> 16) & 0xFF) == 0xCC) - ); + ); #else return false; #endif @@ -5953,12 +6068,12 @@ struct VM { } return (dwError == ERROR_ALREADY_EXISTS); - }; + }; if ( supMutexExist("Sandboxie_SingleInstanceMutex_Control") || supMutexExist("SBIE_BOXED_ServiceInitComplete_Mutex1") - ) { + ) { return core::add(SANDBOXIE); } @@ -6049,47 +6164,47 @@ struct VM { // check if the microarchitecture was made before 2006, which was around the time multi-core processors were implemented auto old_microarchitecture = [&steps]() -> bool { constexpr std::array, 32> old_archs = {{ - // 80486 - {{ 0x4, 0x0, 0x1 }}, - {{ 0x4, 0x0, 0x2 }}, - {{ 0x4, 0x0, 0x3 }}, - {{ 0x4, 0x0, 0x4 }}, - {{ 0x4, 0x0, 0x5 }}, - {{ 0x4, 0x0, 0x7 }}, - {{ 0x4, 0x0, 0x8 }}, - {{ 0x4, 0x0, 0x9 }}, - - // P5 - {{ 0x5, 0x0, 0x1 }}, - {{ 0x5, 0x0, 0x2 }}, - {{ 0x5, 0x0, 0x4 }}, - {{ 0x5, 0x0, 0x7 }}, - {{ 0x5, 0x0, 0x8 }}, - - // P6 - {{ 0x6, 0x0, 0x1 }}, - {{ 0x6, 0x0, 0x3 }}, - {{ 0x6, 0x0, 0x5 }}, - {{ 0x6, 0x0, 0x6 }}, - {{ 0x6, 0x0, 0x7 }}, - {{ 0x6, 0x0, 0x8 }}, - {{ 0x6, 0x0, 0xA }}, - {{ 0x6, 0x0, 0xB }}, - - // Netburst - {{ 0xF, 0x0, 0x6 }}, - {{ 0xF, 0x0, 0x4 }}, - {{ 0xF, 0x0, 0x3 }}, - {{ 0xF, 0x0, 0x2 }}, - {{ 0xF, 0x0, 0x10 }}, - - {{ 0x6, 0x1, 0x5 }}, // Pentium M (Talopai) - {{ 0x6, 0x1, 0x6 }}, // Core (Client) - {{ 0x6, 0x0, 0x9 }}, // Pentium M - {{ 0x6, 0x0, 0xD }}, // Pentium M - {{ 0x6, 0x0, 0xE }}, // Modified Pentium M - {{ 0x6, 0x0, 0xF }} // Core (Client) - }}; + // 80486 + {{ 0x4, 0x0, 0x1 }}, + {{ 0x4, 0x0, 0x2 }}, + {{ 0x4, 0x0, 0x3 }}, + {{ 0x4, 0x0, 0x4 }}, + {{ 0x4, 0x0, 0x5 }}, + {{ 0x4, 0x0, 0x7 }}, + {{ 0x4, 0x0, 0x8 }}, + {{ 0x4, 0x0, 0x9 }}, + + // P5 + {{ 0x5, 0x0, 0x1 }}, + {{ 0x5, 0x0, 0x2 }}, + {{ 0x5, 0x0, 0x4 }}, + {{ 0x5, 0x0, 0x7 }}, + {{ 0x5, 0x0, 0x8 }}, + + // P6 + {{ 0x6, 0x0, 0x1 }}, + {{ 0x6, 0x0, 0x3 }}, + {{ 0x6, 0x0, 0x5 }}, + {{ 0x6, 0x0, 0x6 }}, + {{ 0x6, 0x0, 0x7 }}, + {{ 0x6, 0x0, 0x8 }}, + {{ 0x6, 0x0, 0xA }}, + {{ 0x6, 0x0, 0xB }}, + + // Netburst + {{ 0xF, 0x0, 0x6 }}, + {{ 0xF, 0x0, 0x4 }}, + {{ 0xF, 0x0, 0x3 }}, + {{ 0xF, 0x0, 0x2 }}, + {{ 0xF, 0x0, 0x10 }}, + + {{ 0x6, 0x1, 0x5 }}, // Pentium M (Talopai) + {{ 0x6, 0x1, 0x6 }}, // Core (Client) + {{ 0x6, 0x0, 0x9 }}, // Pentium M + {{ 0x6, 0x0, 0xD }}, // Pentium M + {{ 0x6, 0x0, 0xE }}, // Modified Pentium M + {{ 0x6, 0x0, 0xF }} // Core (Client) + }}; constexpr u8 FAMILY = 0; constexpr u8 EXTMODEL = 1; @@ -6106,7 +6221,7 @@ struct VM { } return false; - }; + }; // self-explanatory if (!(cpu::is_intel() || cpu::is_amd())) { @@ -6166,7 +6281,7 @@ struct VM { auto push = [&thread_database](const char* brand_str, const u8 thread_count) -> void { thread_database->emplace(brand_str, thread_count); - }; + }; // i3 series push("i3-1000G1", 4); @@ -7173,7 +7288,7 @@ struct VM { auto xeon_push = [&xeon_thread_database](const char* brand_str, const u8 thread_count) -> void { xeon_thread_database->emplace(brand_str, thread_count); - }; + }; // Xeon D xeon_push("D-1518", 8); @@ -7480,44 +7595,44 @@ struct VM { auto parse_memory_map = []( struct memory_region* regions, struct map_key key - ) -> DWORD { - HKEY hKey = NULL; - LPCTSTR pszSubKey = key.KeyPath; - LPCTSTR pszValueName = key.ValueName; - LPBYTE lpData = NULL; - DWORD dwLength = 0, count = 0, type = 0;; - DWORD result; - if ((result = RegOpenKeyW(HKEY_LOCAL_MACHINE, reinterpret_cast(pszSubKey), &hKey)) != ERROR_SUCCESS) { - debug("NETTITUDE_VM_MEMORY: Could not get reg key: ", result, " / ", GetLastError()); - return 0; - } + ) -> DWORD { + HKEY hKey = NULL; + LPCTSTR pszSubKey = key.KeyPath; + LPCTSTR pszValueName = key.ValueName; + LPBYTE lpData = NULL; + DWORD dwLength = 0, count = 0, type = 0;; + DWORD result; + if ((result = RegOpenKeyW(HKEY_LOCAL_MACHINE, reinterpret_cast(pszSubKey), &hKey)) != ERROR_SUCCESS) { + debug("NETTITUDE_VM_MEMORY: Could not get reg key: ", result, " / ", GetLastError()); + return 0; + } - if ((result = RegQueryValueExW(hKey, reinterpret_cast(pszValueName), 0, &type, NULL, &dwLength)) != ERROR_SUCCESS) { - debug("NETTITUDE_VM_MEMORY: Could not query hardware key: ", result, " / ", GetLastError()); - return 0; - } + if ((result = RegQueryValueExW(hKey, reinterpret_cast(pszValueName), 0, &type, NULL, &dwLength)) != ERROR_SUCCESS) { + debug("NETTITUDE_VM_MEMORY: Could not query hardware key: ", result, " / ", GetLastError()); + return 0; + } - lpData = (LPBYTE)malloc(dwLength); - RegQueryValueEx(hKey, pszValueName, 0, &type, lpData, &dwLength); - CM_RESOURCE_LIST* resource_list = (CM_RESOURCE_LIST*)lpData; - for (DWORD i = 0; i < resource_list->Count; i++) + lpData = (LPBYTE)malloc(dwLength); + RegQueryValueEx(hKey, pszValueName, 0, &type, lpData, &dwLength); + CM_RESOURCE_LIST* resource_list = (CM_RESOURCE_LIST*)lpData; + for (DWORD i = 0; i < resource_list->Count; i++) + { + for (DWORD j = 0; j < resource_list->List[0].PartialResourceList.Count; j++) { - for (DWORD j = 0; j < resource_list->List[0].PartialResourceList.Count; j++) + if (resource_list->List[i].PartialResourceList.PartialDescriptors[j].Type == 3) { - if (resource_list->List[i].PartialResourceList.PartialDescriptors[j].Type == 3) + if (regions != NULL) { - if (regions != NULL) - { - regions->address = resource_list->List[i].PartialResourceList.PartialDescriptors[j].u.Memory.Start.QuadPart; - regions->size = resource_list->List[i].PartialResourceList.PartialDescriptors[j].u.Memory.Length; - regions++; - } - count++; + regions->address = resource_list->List[i].PartialResourceList.PartialDescriptors[j].u.Memory.Start.QuadPart; + regions->size = resource_list->List[i].PartialResourceList.PartialDescriptors[j].u.Memory.Length; + regions++; } + count++; } } - return count; - }; + } + return count; + }; #define VM_RESOURCE_CHECK_ERROR -1 #define VM_RESOURCE_CHECK_NO_VM 0 @@ -7529,7 +7644,7 @@ struct VM { struct memory_region* phys, int phys_count, struct memory_region* reserved, int reserved_count, struct memory_region* loader_reserved, int loader_reserved_count - ) -> int { + ) -> int { const ULONG64 VBOX_PHYS_LO = 0x0000000000001000ULL; const ULONG64 VBOX_PHYS_HI = 0x000000000009f000ULL; const ULONG64 HYPERV_PHYS_LO = 0x0000000000001000ULL; @@ -7643,39 +7758,39 @@ struct VM { switch (check_result) { // error - case VM_RESOURCE_CHECK_ERROR: - debug("NETTITUDE_VM_MEMORY: unknown error, returned false"); - return false; - break; + case VM_RESOURCE_CHECK_ERROR: + debug("NETTITUDE_VM_MEMORY: unknown error, returned false"); + return false; + break; // no VM - case VM_RESOURCE_CHECK_NO_VM: - debug("NETTITUDE_VM_MEMORY: no VM detected"); - return false; - break; + case VM_RESOURCE_CHECK_NO_VM: + debug("NETTITUDE_VM_MEMORY: no VM detected"); + return false; + break; // Hyper-V - case VM_RESOURCE_CHECK_HYPERV: - debug("NETTITUDE_VM_MEMORY: Hyper-V detected"); - return core::add(HYPERV); - break; + case VM_RESOURCE_CHECK_HYPERV: + debug("NETTITUDE_VM_MEMORY: Hyper-V detected"); + return core::add(HYPERV); + break; // VirtualBox - case VM_RESOURCE_CHECK_VBOX: - debug("NETTITUDE_VM_MEMORY: Vbox detected"); - return core::add(VBOX); - break; + case VM_RESOURCE_CHECK_VBOX: + debug("NETTITUDE_VM_MEMORY: Vbox detected"); + return core::add(VBOX); + break; // Unknown brand, but likely VM - case VM_RESOURCE_CHECK_UNKNOWN_PLATFORM: - debug("NETTITUDE_VM_MEMORY: unknown brand, but likely VM (returned true)"); - return true; - break; + case VM_RESOURCE_CHECK_UNKNOWN_PLATFORM: + debug("NETTITUDE_VM_MEMORY: unknown brand, but likely VM (returned true)"); + return true; + break; - default: - debug("NETTITUDE_VM_MEMORY: returned false as default case"); - return false; - break; + default: + debug("NETTITUDE_VM_MEMORY: returned false as default case"); + return false; + break; } #endif } @@ -7696,7 +7811,7 @@ struct VM { #if (!x86) return false; #else - if (util::hyperv_fucker()) { + if (util::hyper_x()) { return false; } @@ -7781,7 +7896,7 @@ struct VM { } return false; - }; + }; // win api auto IsDirectory1 = [](std::string& strDirName) -> bool { @@ -7804,7 +7919,7 @@ struct VM { } return true; - }; + }; // crt auto IsDirectory = [](std::string& strDirName) -> bool { @@ -7813,7 +7928,7 @@ struct VM { } return false; - }; + }; std::string strDirName = "C:\\Cuckoo"; @@ -7821,7 +7936,7 @@ struct VM { IsDirectory(strDirName) || IsDirectory1(strDirName) || IsDirectory2(strDirName) - ) { + ) { return core::add(CUCKOO); } @@ -7908,7 +8023,7 @@ struct VM { auto cmp = [&](const char* str2) -> bool { return (hostname == str2); - }; + }; if ( cmp("Sandbox") || @@ -7956,7 +8071,7 @@ struct VM { (horiz == 1024 && verti == 768) || (horiz == 800 && verti == 600) || (horiz == 640 && verti == 480) - ) { + ) { return true; } @@ -8031,7 +8146,9 @@ struct VM { #if (!x86) return false; #else - if (util::hyperv_fucker()) { + return core::add(SANDBOXIE); + + if (util::hyper_x()) { return false; } @@ -8046,9 +8163,9 @@ struct VM { debug("CPUID_SIGNATURE: eax = ", eax); switch (eax) { - case hyperv: return core::add(HYPERV); - case nanovisor: return core::add(NANOVISOR); - case simplevisor: return core::add(SIMPLEVISOR); + case hyperv: return core::add(HYPERV); + case nanovisor: return core::add(NANOVISOR); + case simplevisor: return core::add(SIMPLEVISOR); } return false; @@ -8069,7 +8186,7 @@ struct VM { #if (!x86) return false; #else - if (util::hyperv_fucker()) { + if (util::hyper_x()) { return false; } @@ -8085,14 +8202,14 @@ struct VM { cpu::cpuid(eax, ebx, ecx, edx, leaf); switch (register_id) { - case EAX: return eax; - case EBX: return ebx; - case ECX: return ecx; - case EDX: return edx; + case EAX: return eax; + case EBX: return ebx; + case ECX: return ecx; + case EDX: return edx; } return 0; - }; + }; const u32 max_leaf = fetch_register(EAX, 0x40000000); @@ -8145,8 +8262,8 @@ struct VM { (ebx == 0) && (ecx == 0) && (edx == 0) - ); - }; + ); + }; auto leaf_03 = [&]() -> bool { const u32 ecx = fetch_register(ECX, 0x40000003); @@ -8167,9 +8284,9 @@ struct VM { ((edx & (1 << 22)) == 0) && (((edx >> 24) & 0b11) == 0) && ((edx >> 27) == 0) - ); + ); } - }; + }; auto leaf_04 = [&]() -> bool { const u32 eax = fetch_register(EAX, 0x40000004); @@ -8187,7 +8304,7 @@ struct VM { eax == 0 || ecx == 0 || edx != 0 // edx is supposed to be null - ) { + ) { return false; } else { return ( @@ -8196,16 +8313,16 @@ struct VM { ((eax >> 19) == 0) && ((ecx >> 7) == 0) && (edx == 0) - ); + ); } - }; + }; auto leaf_05 = [&]() -> bool { const u32 edx = fetch_register(EDX, 0x40000005); debug("05 edx = ", std::bitset<32>(edx)); debug(" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); return (edx == 0); - }; + }; auto leaf_06 = [&]() -> bool { u32 eax, ebx, ecx, edx = 0; @@ -8225,7 +8342,7 @@ struct VM { ebx != 0 || ecx != 0 || edx != 0 // edx is supposed to be null - ) { + ) { return false; } else { return ( @@ -8234,9 +8351,9 @@ struct VM { (ebx == 0) && (ecx == 0) && (edx == 0) - ); + ); } - }; + }; auto leaf_09 = [&]() -> bool { u32 eax, ebx, ecx, edx = 0; @@ -8256,7 +8373,7 @@ struct VM { ebx != 0 || ecx != 0 || edx == 0 - ) { + ) { return false; } else { return ( @@ -8270,9 +8387,9 @@ struct VM { (((edx >> 5) & 0b1111111111) == 0) && ((edx & (1 << 16)) == 0) && ((edx >> 18) == 0) - ); + ); } - }; + }; auto leaf_0A = [&]() -> bool { u32 eax, ebx, ecx, edx = 0; @@ -8292,7 +8409,7 @@ struct VM { eax == 0 || ecx != 0 || edx != 0 - ) { + ) { return false; } else { return ( @@ -8301,9 +8418,9 @@ struct VM { ((ebx >> 30) == 0) && (ecx == 0) && (edx == 0) - ); + ); } - }; + }; debug("01: ", leaf_01()); debug("03: ", leaf_03()); @@ -8321,7 +8438,7 @@ struct VM { leaf_06() && leaf_09() && leaf_0A() - ) { + ) { return core::add(HYPERV); } @@ -8351,7 +8468,7 @@ struct VM { (ebx == 0x4b4d564b) && (ecx == 0x564b4d56) && (edx == 0x4d) - )) { + )) { return false; } @@ -8361,7 +8478,7 @@ struct VM { (eax & (1 << 8)) && (((eax >> 13) & 0b1111111111) == 0) && ((eax >> 24) == 0) - ) { + ) { return core::add(KVM); } @@ -8391,7 +8508,7 @@ struct VM { // Not sure if it's little endian or big endian, so i'm comparing both ((ecx == 0x4D4D5645) && (edx == 0x43544E49)) || ((ecx == 0x45564D4D) && (edx == 0x494E5443)) - ) { + ) { return core::add(INTEL_KGT); } @@ -8435,9 +8552,7 @@ struct VM { /** * @brief Check for presence of Hyper-V in the Windows Event Logs - * * @author Requiem (https://github.com/NotRequiem) - * * @category Windows */ [[nodiscard]] static bool hyperv_event_logs() try { @@ -8722,7 +8837,7 @@ struct VM { if ( (flag == INVALID) || (flag > enum_size) - ) { + ) { throw std::invalid_argument("Non-flag or invalid flag provided for VM::detect(), aborting"); } @@ -8898,7 +9013,7 @@ struct VM { #endif ss << ". Consult the documentation's flag handler for VM::check()"; throw std::invalid_argument(std::string(text) + ss.str()); - }; + }; // check if flag is out of range if (flag_bit > enum_size) { @@ -8912,7 +9027,7 @@ struct VM { (flag_bit == ENABLE_HYPERV_HOST_REPLACEMENT) || (flag_bit == SPOOFABLE) || (flag_bit == MULTIPLE) - ) { + ) { throw_error("Flag argument must be a technique flag and not a settings flag"); } @@ -9049,7 +9164,7 @@ struct VM { brands.erase(b); brands.emplace(std::make_pair(result, 2)); } - }; + }; auto triple_merger = [&](const char* a, const char* b, const char* c, const char* result) -> void { if ( @@ -9062,14 +9177,14 @@ struct VM { brands.erase(c); brands.emplace(std::make_pair(result, 2)); } - }; + }; if ((brands.count(TMP_HYPERV) > brands.count(TMP_VPC))) { brands.erase(TMP_VPC); } else if ( (brands.count(TMP_HYPERV) == brands.count(TMP_VPC)) && ((brands.count(TMP_HYPERV) > 0) && (brands.count(TMP_VPC) > 0)) - ) { + ) { brands.erase(TMP_HYPERV); brands.erase(TMP_VPC); brands.emplace(std::make_pair(TMP_HYPERV_VPC, 2)); @@ -9111,12 +9226,12 @@ struct VM { std::sort(vec.begin(), vec.end(), []( const brand_element_t &a, const brand_element_t &b - ) { - return a.second < b.second; - }); + ) { + return a.second < b.second; + }); return vec; - }; + }; std::vector vec = sorter(); std::string ret_str = "Unknown"; @@ -9240,7 +9355,7 @@ struct VM { #endif ss << ". Consult the documentation's parameters for VM::add_custom()"; throw std::invalid_argument(std::string(text) + ss.str()); - }; + }; if (percent > 100) { throw_error("Percentage parameter must be between 0 and 100"); @@ -9363,10 +9478,13 @@ std::map VM::core::brand_scoreboard{ { VM::VMWARE_WORKSTATION, 0 }, { VM::VMWARE_FUSION, 0 }, { VM::BHYVE, 0 }, - { VM::QEMU, 0 }, { VM::KVM, 0 }, + { VM::QEMU, 0 }, + { VM::QEMU_KVM, 0 }, { VM::KVM_HYPERV, 0 }, + { VM::QEMU_KVM_HYPERV, 0 }, { VM::HYPERV, 0 }, + { VM::HYPERV_VPC, 0 }, { VM::MSXTA, 0 }, { VM::PARALLELS, 0 }, { VM::XEN, 0 }, @@ -9384,7 +9502,7 @@ std::map VM::core::brand_scoreboard{ { VM::CWSANDBOX, 0 }, { VM::COMODO, 0 }, { VM::BOCHS, 0 }, - { VM::NVMM, 0}, + { VM::NVMM, 0 }, { VM::BSD_VMM, 0 }, { VM::INTEL_HAXM, 0 }, { VM::UNISYS, 0 }, From 506eb2b581224d60495eca1a968759cc797b0c18 Mon Sep 17 00:00:00 2001 From: kernel <77142078+kernelwernel@users.noreply.github.com> Date: Mon, 12 Aug 2024 03:51:10 +0100 Subject: [PATCH 2/5] fixed flag handler and added dhyper-v artifact discards --- auxiliary/vmtest.cpp | 4 ++- src/cli.cpp | 6 ++--- src/vmaware.hpp | 58 +++++++++++++++++++++++--------------------- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/auxiliary/vmtest.cpp b/auxiliary/vmtest.cpp index 3c11d97a..58d105eb 100644 --- a/auxiliary/vmtest.cpp +++ b/auxiliary/vmtest.cpp @@ -24,7 +24,7 @@ #include int main(void) { - const bool test1 = VM::detect(VM::CPUID_SIGNATURE); + //const bool test1 = VM::detect(); //const bool test2 = VM::detect(VM::ALL); //const bool test3 = VM::detect(VM::DEFAULT); //const bool test4 = VM::detect(VM::DEFAULT, VM::ALL); @@ -32,5 +32,7 @@ int main(void) { //const bool test6 = VM::detect(VM::DEFAULT, VM::DISABLE(VM::RDTSC), VM::EXTREME); //const bool test7 = VM::detect(VM::NO_MEMO, VM::EXTREME, VM::MULTIPLE, VM::ENABLE_HYPERV_HOST); //const std::string test8 = VM::brand(); + const uint8_t test9 = VM::percentage(VM::SPOOFABLE); + std::cout << (int)test9 << "\n"; return 0; } \ No newline at end of file diff --git a/src/cli.cpp b/src/cli.cpp index 4b99e29c..14a93595 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -561,8 +561,7 @@ void general() { // meaning "if there's no brand conflicts" if (brand.find(" or ") == std::string::npos) { - const std::string tmp_brand = VM::brand(VM::MULTIPLE, spoofable_setting); - const std::string type_value = type(tmp_brand); + const std::string type_value = type(brand); std::cout << "VM type: "; @@ -578,7 +577,7 @@ void general() { } const char* percent_color = ""; - const std::uint8_t percent = VM::percentage(spoofable_setting); + const std::uint8_t percent = VM::percentage(VM::NULL_ARG/*spoofable_setting*/); if (percent == 0) { percent_color = red; } else if (percent < 25) { percent_color = red_orange; } @@ -635,7 +634,6 @@ void general() { << ansi_exit << "\n\n"; - if ((brand == "Hyper-V artifact (not an actual VM)") && notes_enabled) { std::cout << note << " The result means that the CLI has found Hyper-V, but as an artifact instead of an actual VM. This means that although the hardware values in fact match with Hyper-V due to how it's designed by Microsoft, the CLI has determined you are NOT in a Hyper-V VM.\n\n"; } else if (notes_enabled) { diff --git a/src/vmaware.hpp b/src/vmaware.hpp index 0e6ef26e..272185b9 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -1252,7 +1252,7 @@ struct VM { case KVM_DIRS: return "VM::KVM_DIRS"; case AUDIO: return "VM::AUDIO"; case QEMU_DIR: return "VM::QEMU_DIR"; - case MOUSE_DEVIC: return "VM::MOUSE_DEVIC"; + case MOUSE_DEVICE: return "VM::MOUSE_DEVICE"; case VM_PROCESSES: return "VM::VM_PROCESSES"; case LINUX_USER_HOST: return "VM::LINUX_USER_HOST"; case GAMARUE: return "VM::GAMARUE"; @@ -8642,7 +8642,7 @@ struct VM { struct core { MSVC_DISABLE_WARNING(PADDING) - struct technique { + struct technique { u8 points = 0; // this is the certainty score between 0 and 100 std::function run; // this is the technique function itself bool spoofable = false; // this is to indicate that the technique can be very easily spoofed (not guaranteed) @@ -8654,7 +8654,7 @@ struct VM { }; MSVC_ENABLE_WARNING(PADDING) - static const std::map technique_table; + static const std::map technique_table; static std::vector custom_table; @@ -8738,10 +8738,13 @@ struct VM { flags.test(NO_MEMO) || flags.test(HIGH_THRESHOLD) || flags.test(SPOOFABLE) || + flags.test(NULL_ARG) || flags.test(ENABLE_HYPERV_HOST_REPLACEMENT) || flags.test(MULTIPLE) ) { flags |= DEFAULT; + } else { + throw std::invalid_argument("Invalid flag option found, aborting"); } } @@ -8750,19 +8753,22 @@ struct VM { u16 points = 0; const bool memo_enabled = core::is_disabled(flags, NO_MEMO); - const u16 threshold_points = (core::is_enabled(flags, HIGH_THRESHOLD) ? maximum_points : 200); + const u16 threshold_points = (core::is_enabled(flags, HIGH_THRESHOLD) ? high_threshold_score : 200); // for main technique table for (const auto& tmp : technique_table) { - const u8 technique_macro = tmp.first; + const enum_flags technique_macro = tmp.first; const technique tuple = tmp.second; // check if it's disabled if (core::is_disabled(flags, technique_macro)) { + //debug("disabled: ", util::flag_to_string(technique_macro)); continue; } + // check if it's spoofable, and whether it's enabled if (tuple.spoofable && core::is_disabled(flags, SPOOFABLE)) { + //debug("spoofable: ", util::flag_to_string(technique_macro)); continue; } @@ -8774,12 +8780,15 @@ struct VM { points += data.points; } + //debug("added from cache: ", util::flag_to_string(technique_macro)); + continue; } // run the technique const bool result = tuple.run(); + // accumulate the points if technique detected a VM if (result) { points += tuple.points; @@ -8791,12 +8800,13 @@ struct VM { * there's no point in running the rest of the techniques */ if (shortcut && points >= threshold_points) { - core_debug("VM::run_all(): returned points early due to shortcut option"); + //core_debug("VM::run_all(): returned points early due to shortcut option"); return points; } // store the current technique result to the cache if (memo_enabled) { + //debug("cached: ", util::flag_to_string(technique_macro)); memo::cache_store(technique_macro, result, tuple.points); } } @@ -8841,17 +8851,6 @@ struct VM { throw std::invalid_argument("Non-flag or invalid flag provided for VM::detect(), aborting"); } - if (flag == SPOOFABLE) { - for (const auto& tmp : technique_table) { - const u8 technique_macro = tmp.first; - const technique &tuple = tmp.second; - - if (tuple.spoofable) { - flag_collector.set(technique_macro); - } - } - } - flag_collector.set(flag); } @@ -8961,6 +8960,7 @@ struct VM { } flag_collector.reset(); + global_flags.reset(); handleArgs(std::forward(args)...); @@ -8999,7 +8999,7 @@ struct VM { * @return bool * @link https://github.com/kernelwernel/VMAware/blob/main/docs/documentation.md#vmcheck */ - [[nodiscard]] static bool check(const u8 flag_bit + [[nodiscard]] static bool check(const enum_flags flag_bit // clang doesn't support std::source_location for some reason #if (CPP >= 20 && !CLANG) , const std::source_location& loc = std::source_location::current() @@ -9119,9 +9119,9 @@ struct VM { #else constexpr const char* TMP_QEMU = QEMU; constexpr const char* TMP_KVM = KVM; - constexpr const char* TMP_QEMU_KVM = "QEMU+KVM"; + constexpr const char* TMP_QEMU_KVM = QEMU_KVM; constexpr const char* TMP_KVM_HYPERV = KVM_HYPERV; - constexpr const char* TMP_QEMU_KVM_HYPERV = "QEMU+KVM Hyper-V Enlightenment"; + constexpr const char* TMP_QEMU_KVM_HYPERV = QEMU_KVM_HYPERV; constexpr const char* TMP_VMWARE = VMWARE; constexpr const char* TMP_EXPRESS = VMWARE_EXPRESS; @@ -9132,7 +9132,7 @@ struct VM { constexpr const char* TMP_VPC = VPC; constexpr const char* TMP_HYPERV = HYPERV; - constexpr const char* TMP_HYPERV_VPC = "Microsoft Virtual PC/Hyper-V"; + constexpr const char* TMP_HYPERV_VPC = HYPERV_VPC; constexpr const char* TMP_AZURE = AZURE_HYPERV; constexpr const char* TMP_NANOVISOR = NANOVISOR; constexpr const char* TMP_HYPERV_ARTIFACT = HYPERV_ARTIFACT; @@ -9153,13 +9153,17 @@ struct VM { if (brands.size() == 1) { return brands.begin()->first; + } else if (brands.size() > 1) { + if (brands.find(TMP_HYPERV_ARTIFACT) != brands.end()) { + brands.erase(TMP_HYPERV_ARTIFACT); + } } auto merger = [&](const char* a, const char* b, const char* result) -> void { if ( (brands.count(a) > 0) && (brands.count(b) > 0) - ) { + ) { brands.erase(a); brands.erase(b); brands.emplace(std::make_pair(result, 2)); @@ -9171,7 +9175,7 @@ struct VM { (brands.count(a) > 0) && (brands.count(b) > 0) && (brands.count(c) > 0) - ) { + ) { brands.erase(a); brands.erase(b); brands.erase(c); @@ -9307,7 +9311,7 @@ struct VM { */ template static u8 percentage(Args ...args) { - flagset flags = core::arg_handler(args...); + const flagset flags = core::arg_handler(args...); const u16 points = core::run_all(flags, SHORTCUT); u8 percent = 0; @@ -9449,7 +9453,7 @@ struct VM { throw_error("The flag is not a technique flag"); } - using table_t = std::map; + using table_t = std::map; auto modify = [](table_t &table, const enum_flags flag, const u8 percent) -> void { core::technique &tmp = table.at(flag); @@ -9515,7 +9519,7 @@ std::map VM::core::brand_scoreboard{ { VM::AZURE_HYPERV, 0 }, { VM::NANOVISOR, 0 }, { VM::SIMPLEVISOR, 0 }, - { VM::HYPERV_ARTIFACT, 0 } + { VM::HYPERV_ARTIFACT, 1 } }; @@ -9604,7 +9608,7 @@ std::vector VM::core::custom_table = { // the 0~100 points are debatable, but I think it's fine how it is. Feel free to disagree. -const std::map VM::core::technique_table = { +const std::map VM::core::technique_table = { // FORMAT: VM:: = { certainty%, function pointer, is spoofable? } { VM::VMID, { 100, VM::vmid, false } }, From 272e14f3437ca1a0394177dc5e2a75c8af941bea Mon Sep 17 00:00:00 2001 From: kernel <77142078+kernelwernel@users.noreply.github.com> Date: Mon, 12 Aug 2024 04:06:57 +0100 Subject: [PATCH 3/5] Delete deprecation.md --- deprecation.md | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 deprecation.md diff --git a/deprecation.md b/deprecation.md deleted file mode 100644 index 863c4630..00000000 --- a/deprecation.md +++ /dev/null @@ -1,22 +0,0 @@ -> [!WARNING] -> The library has been deprecated as of 1.7.1 release **only for production environments**. -> -> In other words, the library should NOT be used for critical projects where an integral program (anticheat, paid software, etc...) or anything serious where a false detection of a VM could be catastrophic. The library should now instead be used as an interactive toy piece of C++ code for people to play around with in a non-serious manner. -> -> The CLI is not affected by this usage deprecation, however, as the CLI was already treated as a toy program from the start. -> -> -> The deprecation is due to a few reasons: -> ## 1. **Hyper-V:** -> - Microsoft's Hyper-V has been a complete nightmare since this project began. It took me and [@Requiem](https://github.com/NotRequiem) a while to discover that Hyper-V (upon installation) changes hardware values by making it seem it's actually running in a VM even though the program is running on the host [[example](https://github.com/kernelwernel/VMAware/issues/75)]. This mechanism is even worse considering that Windows 11 has Hyper-V installed by default, making Windows 11 completely impossible to detect whether it's running in a manually intended Hyper-V VM by the user, or the leftover artifacts of what Hyper-V vomited all over the system when it was installed, which gave the library a false positive on the host system. Although Windows 10 must allow the user to install Hyper-V manually, this does not make the issue any better to handle for us. Hyper-V has been the main reason why I can't sleep well at night for the past half a year. -> -> ## 2. **Spoofability:** -> - The library does tackle spoofable techniques by skipping over them by default, unless whether `VM::SPOOFABLE` (for the library) or `--spoofable` (for the CLI) options were given. Although this is a fairly practical way to combat against the "easily" spoofable techniques, everything is technically spoofable. One anti-anti-VM project called [VMwareHardenedLoader](https://github.com/hzqst/VmwareHardenedLoader) is at a massive advantage against the library, and there's nothing we can do about it realistically. The library struggled to find anything of value EVEN with spoofable techniques enabled. There's also the problem that 1/3 of all the techniques in the library are considered "spoofable". It doesn't take a genius to figure out that this is a really bad VM detection library if 33% of all techniques can't be ran by default. -> -> ## 3. **Practicality:** -> - The main goal of the project was for the aforementioned category of "integral" programs to detect a VM in a practical and convenient way. If we knew the full extent of the pitfalls (the Hyper-V and spoofability problems mentioned above) from the start, this project wouldn't had been designed with this intention. What I thought was a practical library when starting out has now turned into an ineffective edgecase hell the more we discovered about the reality of VM detections. Not only this, there's the assumption of the fact that this library could be used by serious devs (or worse, companies) who might have a false sense of integrity for how effective the library is for their software. For example, having a gamer get declined to run their newly bought game because the library falsely detected the system to be a Hyper-V VM is an absolute fucking nuclear proportion disaster. -> -> This is just a deprecation of **how** the library should be used, however. Development will still continue as usual, and the library will be improved more and more as time passes. But the core issues that were mentioned will linger, and the deprecation will not be lifted for a while unless a solution will be discovered. - - -## TL;DR: Too many spoofable techniques, library has become impractial, Hyper-V makes me want to kill myself in an infinite loop of an infinite lifetimes. \ No newline at end of file From 4b0ec3d194a4d87362c0834638330f2b3614f4ee Mon Sep 17 00:00:00 2001 From: kernel <77142078+kernelwernel@users.noreply.github.com> Date: Mon, 12 Aug 2024 05:32:02 +0100 Subject: [PATCH 4/5] flag fix and readme --- README.md | 9 +++++++++ deprecation.md | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 deprecation.md diff --git a/README.md b/README.md index 9220beef..4717af6d 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,15 @@ The library is:
+> [!CAUTION] +**DO NOT USE THIS LIBRARY FOR CRITICAL SOFTWARE** (i.e. anti-cheats, proprietary software, paid software, etc...) +> +> However, a solution is in development that will allow this in the next release which should be soon. +> +> The full reason can be found [here](deprecation.md) + + + ## Example 🧪 ```cpp #include "vmaware.hpp" diff --git a/deprecation.md b/deprecation.md new file mode 100644 index 00000000..863c4630 --- /dev/null +++ b/deprecation.md @@ -0,0 +1,22 @@ +> [!WARNING] +> The library has been deprecated as of 1.7.1 release **only for production environments**. +> +> In other words, the library should NOT be used for critical projects where an integral program (anticheat, paid software, etc...) or anything serious where a false detection of a VM could be catastrophic. The library should now instead be used as an interactive toy piece of C++ code for people to play around with in a non-serious manner. +> +> The CLI is not affected by this usage deprecation, however, as the CLI was already treated as a toy program from the start. +> +> +> The deprecation is due to a few reasons: +> ## 1. **Hyper-V:** +> - Microsoft's Hyper-V has been a complete nightmare since this project began. It took me and [@Requiem](https://github.com/NotRequiem) a while to discover that Hyper-V (upon installation) changes hardware values by making it seem it's actually running in a VM even though the program is running on the host [[example](https://github.com/kernelwernel/VMAware/issues/75)]. This mechanism is even worse considering that Windows 11 has Hyper-V installed by default, making Windows 11 completely impossible to detect whether it's running in a manually intended Hyper-V VM by the user, or the leftover artifacts of what Hyper-V vomited all over the system when it was installed, which gave the library a false positive on the host system. Although Windows 10 must allow the user to install Hyper-V manually, this does not make the issue any better to handle for us. Hyper-V has been the main reason why I can't sleep well at night for the past half a year. +> +> ## 2. **Spoofability:** +> - The library does tackle spoofable techniques by skipping over them by default, unless whether `VM::SPOOFABLE` (for the library) or `--spoofable` (for the CLI) options were given. Although this is a fairly practical way to combat against the "easily" spoofable techniques, everything is technically spoofable. One anti-anti-VM project called [VMwareHardenedLoader](https://github.com/hzqst/VmwareHardenedLoader) is at a massive advantage against the library, and there's nothing we can do about it realistically. The library struggled to find anything of value EVEN with spoofable techniques enabled. There's also the problem that 1/3 of all the techniques in the library are considered "spoofable". It doesn't take a genius to figure out that this is a really bad VM detection library if 33% of all techniques can't be ran by default. +> +> ## 3. **Practicality:** +> - The main goal of the project was for the aforementioned category of "integral" programs to detect a VM in a practical and convenient way. If we knew the full extent of the pitfalls (the Hyper-V and spoofability problems mentioned above) from the start, this project wouldn't had been designed with this intention. What I thought was a practical library when starting out has now turned into an ineffective edgecase hell the more we discovered about the reality of VM detections. Not only this, there's the assumption of the fact that this library could be used by serious devs (or worse, companies) who might have a false sense of integrity for how effective the library is for their software. For example, having a gamer get declined to run their newly bought game because the library falsely detected the system to be a Hyper-V VM is an absolute fucking nuclear proportion disaster. +> +> This is just a deprecation of **how** the library should be used, however. Development will still continue as usual, and the library will be improved more and more as time passes. But the core issues that were mentioned will linger, and the deprecation will not be lifted for a while unless a solution will be discovered. + + +## TL;DR: Too many spoofable techniques, library has become impractial, Hyper-V makes me want to kill myself in an infinite loop of an infinite lifetimes. \ No newline at end of file From 99a6a8ce6335b17be46c8ba0a214850d9165b287 Mon Sep 17 00:00:00 2001 From: kernel <77142078+kernelwernel@users.noreply.github.com> Date: Mon, 12 Aug 2024 05:35:35 +0100 Subject: [PATCH 5/5] fixed error and unfucked hyper-v test brand --- src/vmaware.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vmaware.hpp b/src/vmaware.hpp index 4b57757b..2a57017a 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -8146,7 +8146,7 @@ struct VM { #if (!x86) return false; #else - if (util::hyperv_fucker()) { + if (util::hyper_x()) { return false; } @@ -9517,7 +9517,7 @@ std::map VM::core::brand_scoreboard{ { VM::AZURE_HYPERV, 0 }, { VM::NANOVISOR, 0 }, { VM::SIMPLEVISOR, 0 }, - { VM::HYPERV_ARTIFACT, 1 } + { VM::HYPERV_ARTIFACT, 0 } };