diff --git a/.github/workflows/build_run_win_32.bat b/.github/workflows/build_run_win_32.bat index 55a3b7c7..34d29c53 100644 --- a/.github/workflows/build_run_win_32.bat +++ b/.github/workflows/build_run_win_32.bat @@ -2,7 +2,7 @@ echo on cd "%~dp0..\.." mkdir build cd build -cmake -G "Visual Studio 17 2022" -A Win32 -S .. +cmake -DCMAKE_BUILD_TYPE=Debug -G "Visual Studio 17 2022" -A Win32 -S .. "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\devenv.com" "VMAware.sln" /Build "Release|Win32" /Project "vmaware" /ProjectConfig "Release|Win32" cd Release vmaware.exe diff --git a/.github/workflows/build_run_win_64.bat b/.github/workflows/build_run_win_64.bat index 546d164d..7e16a057 100644 --- a/.github/workflows/build_run_win_64.bat +++ b/.github/workflows/build_run_win_64.bat @@ -2,7 +2,7 @@ echo on cd "%~dp0..\.." mkdir build cd build -cmake -G "Visual Studio 17 2022" -A x64 -S .. +cmake -DCMAKE_BUILD_TYPE=Debug -G "Visual Studio 17 2022" -A x64 -S .. "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\devenv.com" "VMAware.sln" /Build "Release|x64" /Project "vmaware" /ProjectConfig "Release|x64" cd Release vmaware.exe diff --git a/CMakeLists.txt b/CMakeLists.txt index fe4f6652..a4632255 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,7 @@ set(TARGET "vmaware") if (MSVC) if(CMAKE_BUILD_TYPE MATCHES "Debug") MESSAGE(STATUS "Build set to debug mode") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Od /RTC1 /debug") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Od /debug") elseif(CMAKE_BUILD_TYPE MATCHES "Release") MESSAGE(STATUS "Build set to release mode") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /O2") diff --git a/README.md b/README.md index ec5f0518..c3ce67f7 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ And if you found this project useful, a star would be appreciated :) - Tom Liston + Ed Skoudis - [Tobias Klein](https://www.trapkit.de/index.html) - [(S21sec) Alfredo Omella](https://www.s21sec.com/) -- [(eEye Digital Security) Derek Soeder]() +- [hfiref0x](https://github.com/hfiref0x)
diff --git a/TODO.md b/TODO.md index 52cd3559..6bfe8891 100644 --- a/TODO.md +++ b/TODO.md @@ -18,10 +18,15 @@ - [ ] fix memoization - [X] add a python script to automatically set the lines of the seperate sections in the header - [ ] add C++20 concepts for the VM::add_custom() function -- [ ] check for valid monitor technique +- [X] check for valid monitor technique - [ ] fix the is_admin code for windows -- [ ] test it on compiler explorer with windows 32-bit settings +- [X] test it on compiler explorer with windows 32-bit settings +- [ ] upload the lib to dnf +- [ ] upload the lib to apt +- [X] add ARM support +- [ ] look into what `fv-az663-325` is +- [ ] implement techniques from [here](https://labs.nettitude.com/blog/vm-detection-tricks-part-3-hyper-v-raw-network-protocol/) +- [ ] add multiple choice for VM::brand() # Distant plans -- add ARM support - add the library to conan.io when released diff --git a/docs/documentation.md b/docs/documentation.md index f6497e59..a96e0fbc 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -79,11 +79,18 @@ int main() { This will essentially return the VM brand as a `std::string`. The exact possible brand string return values are: - `VMware` - `VirtualBox` +- `VMware` +- `VMware Express` +- `VMware ESX` +- `VMware GSX` +- `VMware Workstation` - `bhyve` - `KVM` - `QEMU` - `QEMU+KVM` - `Microsoft Hyper-V` +- `Virtual PC` +- `Microsoft Virtual PC/Hyper-V` - `Microsoft x86-to-ARM` - `Parallels` - `Xen HVM` @@ -94,7 +101,6 @@ This will essentially return the VM brand as a `std::string`. The exact possible - `Docker` - `Wine` - `Virtual Apple` -- `Virtual PC` - `Anubis` - `JoeBox` - `Thread Expert` @@ -267,9 +273,9 @@ VMAware provides a convenient way to not only check for VMs, but also have the f | `VM::PARALLELS_VM` | Check for indications of Parallels VM | Windows | 50% | | | | `VM::RDTSC_VMEXIT` | Check for RDTSC technique with VMEXIT | Yes | 50% | | | | `VM::LOADED_DLLS` | Check for DLLs of multiple VM brands | Windows | 75% | | GPL | -| `VM::QEMU_BRAND` | Check for QEMU CPU brand with cpuid | Yes | 100% | | | +| `VM::QEMU_BRAND` | Check for QEMU CPU brand with cpuid | Yes | 100% | | | | `VM::BOCHS_CPU` | Check for Bochs cpuid emulation oversights | Yes | 95% | | | -| `VM::VPC_BOARD` | Check for VPC specific string in motherboard manufacturer | Windows | 20% | | | +| `VM::VPC_BOARD` | Check for VPC specific string in motherboard manufacturer | Windows | 20% | | | | `VM::HYPERV_WMI` | Check for Hyper-V wmi output | Windows | 80% | | | | `VM::HYPERV_REG` | Check for Hyper-V strings in registry | Windows | 80% | | | | `VM::BIOS_SERIAL` | Check if BIOS serial number is null | Windows | 60% | | | diff --git a/src/cli.cpp b/src/cli.cpp index 57b2f498..d38257a4 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -218,7 +218,7 @@ int main(int argc, char* argv[]) { checker(VM::HYPERV_REG, "Hyper-V registry"); checker(VM::HYPERV_WMI, "Hyper-V WMI output"); checker(VM::VBOX_FOLDERS, "VirtualBox shared folders"); - checker(VM::VBOX_MSSMBIOS, "VirtualBox MSSMBIOS"); + checker(VM::MSSMBIOS, "MSSMBIOS"); checker(VM::MAC_MEMSIZE, "MacOS hw.memsize"); checker(VM::MAC_IOKIT, "MacOS registry IO-kit"); checker(VM::IOREG_GREP, "IO registry grep"); @@ -247,15 +247,15 @@ int main(int argc, char* argv[]) { checker(VM::VMWARE_IOPORTS, "/proc/ioports file"); checker(VM::VMWARE_SCSI, "/proc/scsi/scsi file"); checker(VM::VMWARE_DMESG, "VMware dmesg"); - checker(VM::VMWARE_EMULATION, "VMware emulation mode"); checker(VM::VMWARE_STR, "STR instruction"); checker(VM::VMWARE_BACKDOOR, "VMware IO port backdoor"); - checker(VM::SMSW, "SMSW instruction"); checker(VM::VMWARE_PORT_MEM, "VMware port memory"); + checker(VM::SMSW, "SMSW instruction"); + checker(VM::MUTEX, "mutex strings"); std::printf("\n"); - const std::string brand = VM::brand(); + const std::string brand = VM::brand(VM::MULTIPLE); std::cout << "VM brand: " << (brand == "Unknown" ? red : green) << brand << ansi_exit << "\n"; @@ -309,7 +309,7 @@ int main(int argc, char* argv[]) { version(); return 0; } else if (cmp(arg, "-b") || cmp(arg, "--brand")) { - std::cout << VM::brand() << "\n"; + std::cout << VM::brand(VM::MULTIPLE) << "\n"; return 0; } else if (cmp(arg, "-p") || cmp(arg, "--percent")) { std::cout << static_cast(VM::percentage()) << "\n"; diff --git a/src/vmaware.hpp b/src/vmaware.hpp index 3d80b614..e035f5ca 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -294,7 +294,7 @@ struct VM { HYPERV_REG, BIOS_SERIAL, VBOX_FOLDERS, - VBOX_MSSMBIOS, + MSSMBIOS, MAC_MEMSIZE, MAC_IOKIT, IOREG_GREP, @@ -318,14 +318,15 @@ struct VM { VMWARE_IOPORTS, VMWARE_SCSI, VMWARE_DMESG, - VMWARE_EMULATION, VMWARE_STR, VMWARE_BACKDOOR, VMWARE_PORT_MEM, SMSW, + MUTEX, EXTREME, NO_MEMO, - WIN_HYPERV_DEFAULT + WIN_HYPERV_DEFAULT, + MULTIPLE }; private: static constexpr u8 enum_size = __LINE__ - enum_line_start - 4; // get enum size @@ -576,18 +577,6 @@ struct VM { qnx = " QNXQVMBSQG ", virtapple = "VirtualApple"; -#if (CPP >= 17) - constexpr std::array IDs{ -#else - std::array IDs { -#endif - bhyve, kvm, qemu, - hyperv, parallels, parallels, - parallels2, vmware, vbox, - xen, acrn, qnx, - virtapple - }; - 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); @@ -611,36 +600,48 @@ struct VM { return str; }; - std::stringstream ss; - ss << strconvert(sig_reg[0]); - ss << strconvert(sig_reg[2]); - ss << strconvert(sig_reg[1]); + std::stringstream ss1; + std::stringstream ss2; + + ss1 << strconvert(sig_reg[0]); + ss1 << strconvert(sig_reg[1]); + ss1 << strconvert(sig_reg[2]); + + ss2 << strconvert(sig_reg[0]); + ss2 << strconvert(sig_reg[2]); + ss2 << strconvert(sig_reg[1]); - brand = ss.str(); + std::string brand1 = ss1.str(); + std::string brand2 = ss2.str(); - debug(technique_name, brand); + debug(technique_name, brand1); + debug(technique_name, brand2); #if (CPP < 17) // bypass compiler warning about unused parameter, ignore this UNUSED(technique_name); #endif - const bool found = (std::find(std::begin(IDs), std::end(IDs), brand) != std::end(IDs)); - - if (found) { - if (brand == qemu) { return core::add(QEMU); } - if (brand == vmware) { return core::add(VMWARE); } - if (brand == vbox) { return core::add(VBOX); } - if (brand == bhyve) { return core::add(BHYVE); } - if (brand == kvm) { return core::add(KVM); } - if (brand == hyperv) { return core::add(HYPERV); } - if (brand == xta) { return core::add(MSXTA); } - if (brand == parallels) { return core::add(PARALLELS); } - if (brand == parallels2) { return core::add(PARALLELS); } - if (brand == xen) { return core::add(XEN); } - if (brand == acrn) { return core::add(ACRN); } - if (brand == qnx) { return core::add(QNX); } - if (brand == virtapple) { return core::add(VAPPLE); } + const std::vector brand_streams = { brand1, brand2 }; + + for (const auto &tmp_brand : brand_streams) { + if (tmp_brand == qemu) { return core::add(QEMU); } + if (tmp_brand == vmware) { return core::add(VMWARE); } + if (tmp_brand == vbox) { return core::add(VBOX); } + if (tmp_brand == bhyve) { return core::add(BHYVE); } + if (tmp_brand == kvm) { return core::add(KVM); } + if (tmp_brand == xta) { return core::add(MSXTA); } + if (tmp_brand == parallels) { return core::add(PARALLELS); } + if (tmp_brand == parallels2) { return core::add(PARALLELS); } + if (tmp_brand == xen) { return core::add(XEN); } + if (tmp_brand == acrn) { return core::add(ACRN); } + if (tmp_brand == qnx) { return core::add(QNX); } + if (tmp_brand == virtapple) { return core::add(VAPPLE); } + if (tmp_brand == hyperv) { + bool tmp = core::add(VPC); + UNUSED(tmp); + return core::add(HYPERV); + } } /** @@ -650,7 +651,7 @@ struct VM { * but the Wikipedia article on CPUID says it's * "KVMKVMKVM\0\0\0", like wtf???? */ - if (util::find(brand, "KVM")) { + if (util::find(brand1, "KVM") || util::find(brand2, "KVM")) { return core::add(KVM); } @@ -1980,19 +1981,19 @@ struct VM { #else const char* vendor_file = "/sys/devices/virtual/dmi/id/chassis_vendor"; - if (util::exists(vendor_file)) { - const std::string vendor = util::read_file(vendor_file); - - // TODO: More can be definitely added, I only tried QEMU and VMware so far - if (vendor == "QEMU") { return core::add(QEMU); } - if (vendor == "Oracle Corporation") { return core::add(VMWARE); } - - debug("CVENDOR: ", "unknown vendor = ", vendor); - } - else { + if (!util::exists(vendor_file)) { debug("CVENDOR: ", "file doesn't exist"); + return false; } + const std::string vendor = util::read_file(vendor_file); + + // TODO: More can definitely be added, I only tried QEMU and VMware so far + if (vendor == "QEMU") { return core::add(QEMU); } + if (vendor == "Oracle Corporation") { return core::add(VMWARE); } + + debug("CVENDOR: ", "unknown vendor = ", vendor); + return false; #endif } @@ -2592,8 +2593,8 @@ struct VM { } } - debug("VM_FILES: vmware score: ", vmware); - debug("VM_FILES: vbox score: ", vbox); + debug("VM_FILES: vmware score: ", static_cast(vmware)); + debug("VM_FILES: vbox score: ", static_cast(vbox)); if (vbox > vmware) { return core::add(VBOX); @@ -4172,14 +4173,14 @@ struct VM { /** - * @brief Check VirtualBox MSSMBIOS registry for VM-specific strings + * @brief Check MSSMBIOS registry for VM-specific strings * @category Windows * @note slightly modified from original code * @author @waleedassar * @link https://pastebin.com/fPY4MiYq */ - [[nodiscard]] static bool vbox_mssmbios() try { - if (core::disabled(VBOX_MSSMBIOS)) { + [[nodiscard]] static bool mssmbios() try { + if (core::disabled(MSSMBIOS)) { return false; } @@ -4223,7 +4224,7 @@ struct VM { } MSVC_DISABLE_WARNING(5045) - auto ScanDataForString = [](unsigned char* data, unsigned long data_length, unsigned char* string2) -> unsigned char* { + auto ScanDataForString = [](unsigned char* data, unsigned long data_length, unsigned char* string2) -> unsigned char* { std::size_t string_length = strlen(reinterpret_cast(string2)); for (std::size_t i = 0; i <= (data_length - string_length); i++) { @@ -4233,27 +4234,27 @@ struct VM { } return 0; - }; + }; auto AllToUpper = [](char* str, std::size_t len) { for (std::size_t i = 0; i < len; ++i) { str[i] = static_cast(std::toupper(static_cast(str[i]))); } - }; + }; MSVC_ENABLE_WARNING(5045) - AllToUpper(p, length); + AllToUpper(p, length); // cleaner and better shortcut than typing reinterpret_cast a million times auto cast = [](char* p) -> unsigned char* { return reinterpret_cast(p); - }; + }; unsigned char* x1 = ScanDataForString(cast(p), length, (unsigned char*)("INNOTEK GMBH")); unsigned char* x2 = ScanDataForString(cast(p), length, (unsigned char*)("VIRTUALBOX")); unsigned char* x3 = ScanDataForString(cast(p), length, (unsigned char*)("SUN MICROSYSTEMS")); - unsigned char* x4 = ScanDataForString(cast(p), length, (unsigned char*)("VIRTUAL MACHINE")); - unsigned char* x5 = ScanDataForString(cast(p), length, (unsigned char*)("VBOXVER")); + unsigned char* x4 = ScanDataForString(cast(p), length, (unsigned char*)("VBOXVER")); + unsigned char* x5 = ScanDataForString(cast(p), length, (unsigned char*)("VIRTUAL MACHINE")); if (x1 || x2 || x3 || x4 || x5) { is_vm = true; @@ -4270,6 +4271,10 @@ struct VM { RegCloseKey(hk); if (is_vm) { + if (x5) { + return true; + } + return core::add(VBOX); } @@ -5208,7 +5213,7 @@ struct VM { #if (!MSVC) return false; #else - constexpr std::array, 9> files = { { + constexpr std::array, 9> files = { { { VPC, "c:\\windows\\system32\\drivers\\vmsrvc.sys" }, { VPC, "c:\\windows\\system32\\drivers\\vpc-s3.sys" }, { PARALLELS, "c:\\windows\\system32\\drivers\\prleth.sys" }, @@ -5391,70 +5396,6 @@ struct VM { } - /** - * @brief Check VMware emulation test - * @category Windows, x86 - * @note Derek Soeder's (eEye Digital Security) VMware emulation test - * @copyright BSD clause 2 - */ -#if (x86_32 && MSVC) - #define EndUserModeAddress (*(UINT_PTR*)0x7FFE02B4) - typedef LONG (NTAPI *NTSETLDTENTRIES)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); - - static int handle_exception(LPEXCEPTION_POINTERS lpep, bool &is_vm) { - if ((UINT_PTR)(lpep->ExceptionRecord->ExceptionAddress) > EndUserModeAddress) { - is_vm = true; - } - - return (EXCEPTION_EXECUTE_HANDLER); - } - - [[nodiscard]] static bool vmware_emul() { - if (core::disabled(VMWARE_EMULATION)) { - return false; - } - - NTSETLDTENTRIES ZwSetLdtEntries; - LDT_ENTRY csdesc; - bool is_vm = false; - - ZwSetLdtEntries = reinterpret_cast(GetProcAddress(GetModuleHandle ("ntdll.dll"), "ZwSetLdtEntries")); - - memset (&csdesc, 0, sizeof (csdesc)); - - csdesc.LimitLow = (WORD)(EndUserModeAddress >> 12); - csdesc.HighWord.Bytes.Flags1 = 0xFA; - csdesc.HighWord.Bytes.Flags2 = 0xC0 | ((EndUserModeAddress >> 28) & 0x0F); - - ZwSetLdtEntries (0x000F, ((DWORD*)&csdesc)[0], ((DWORD*)&csdesc)[1], 0, 0, 0); - - __try { - __asm { - pop eax - push 0x000F - push eax - retf - } - __asm { - or eax, -1 - jmp eax - } - } - __except (handle_exception(GetExceptionInformation(), is_vm)) { } - - if (is_vm) { - return core::add(VMWARE); - } - - return false; - } -#else - [[nodiscard]] static bool vmware_emul() { - return false; - } -#endif - - /** * @brief Check for official VMware io port backdoor technique * @category Windows, x86 @@ -5599,6 +5540,62 @@ struct VM { } + /** + * @brief Check for mutex strings of VM brands + * @category Windows, x86 + * @note from VMDE project + * @author hfiref0x + * @copyright MIT + */ + [[nodiscard]] static bool mutex() try { + if (core::disabled(MUTEX)) { + return false; + } + +#if (!MSVC) + return false; +#else + auto supMutexExist = [](const char* lpMutexName) -> bool { + DWORD dwError; + HANDLE hObject = NULL; + if (lpMutexName == NULL) { + return false; + } + + SetLastError(0); + hObject = CreateMutex(NULL, FALSE, lpMutexName); + dwError = GetLastError(); + + if (hObject) { + CloseHandle(hObject); + } + + return (dwError == ERROR_ALREADY_EXISTS); + }; + + if ( + supMutexExist("Sandboxie_SingleInstanceMutex_Control") || + supMutexExist("SBIE_BOXED_ServiceInitComplete_Mutex1") + ) { + return core::add(SANDBOXIE); + } + + if (supMutexExist("MicrosoftVirtualPC7UserServiceMakeSureWe'reTheOnlyOneMutex")) { + return core::add(VPC); + } + + if (supMutexExist("Frz_State")) { + return true; + } + + return false; +#endif + } + catch (...) { + debug("MUTEX: catched error, returned false"); + return false; + } + struct core { MSVC_DISABLE_WARNING(4820) struct technique { @@ -5619,7 +5616,7 @@ struct VM { #endif // directly return when adding a brand to the scoreboard for a more succint expression -#if (MSVC) +#if (MSVC) __declspec(noalias) #elif (LINUX) [[gnu::const]] @@ -5695,7 +5692,7 @@ struct VM { #endif ss << ". Consult the documentation's flag handler for VM::check()"; throw std::invalid_argument(std::string(text) + ss.str()); - }; + }; if (p_flag > enum_size) { throw_error("Flag argument must be a valid"); @@ -5708,7 +5705,7 @@ struct VM { if ( (p_flag == NO_MEMO) || \ (p_flag == EXTREME) - ) { + ) { throw_error("Flag argument must be a technique flag and not a settings flag"); } @@ -5723,7 +5720,7 @@ struct VM { auto it = core::table.find(p_flag); - if (/*VMAWARE_UNLIKELY*/(it == core::table.end())) { + if ((it == core::table.end())) { throw_error("Flag is not known"); } @@ -5738,72 +5735,55 @@ struct VM { /** * @brief Fetch the VM brand - * @param any combination of flags, can be optional + * @param either nothing or VM::MULTIPLE * @return std::string * @returns VMware, VirtualBox, KVM, bhyve, QEMU, Microsoft Hyper-V, Microsoft x86-to-ARM, Parallels, Xen HVM, ACRN, QNX hypervisor, Hybrid Analysis, Sandboxie, Docker, Wine, Virtual Apple, Virtual PC, Unknown * @link https://github.com/kernelwernel/VMAware/blob/main/docs/documentation.md#vmbrand */ - [[nodiscard]] static std::string brand(const flagset p_flags = DEFAULT) { + [[nodiscard]] static std::string brand(u8 is_multiple = false) { { // this is added to set the brand scoreboard table - u16 tmp = core::run_all(p_flags); + u16 tmp = core::run_all(DEFAULT); UNUSED(tmp); } - const char* current_brand = ""; - - // fetch the brand with the most points in the scoreboard -#if (CPP >= 20) - auto it = std::ranges::max_element(core::brand_scoreboard, {}, - [](const auto& pair) { - return pair.second; - } - ); + #define brands core::brand_scoreboard - if (it != core::brand_scoreboard.end()) { - if ( - std::none_of(core::brand_scoreboard.cbegin(), core::brand_scoreboard.cend(), - [](const auto& pair) { - return pair.second; - } - ) - ) { - current_brand = "Unknown"; - } - else { - current_brand = it->first; - } +#ifdef __VMAWARE_DEBUG__ + for (const auto p : brands) { + debug("scoreboard: ", (int)p.second, " : ", p.first); } - else { - current_brand = "Unknown"; +#endif + + if (is_multiple == VM::MULTIPLE) { + is_multiple = true; + } else if (is_multiple != 0) { + throw std::invalid_argument("Flag for VM::brand() must either be empty or VM::MULTIPLE. Consult the documentation's flag handler for VM::check()"); } -#else - #if (MSVC) - int max = 0; - #else - u8 max = 0; - #endif - #if (CPP >= 17) - for (const auto& [brand, points] : core::brand_scoreboard) { + const char* current_brand = ""; + i32 max = 0; + + // both do the same thing +#if (CPP >= 17) + for (const auto& [brand, points] : brands) { if (points > max) { current_brand = brand; max = points; } } - #else - for (auto it = core::brand_scoreboard.cbegin(); it != core::brand_scoreboard.cend(); ++it) { +#else + for (auto it = brands.cbegin(); it != brands.cend(); ++it) { if (it->second > max) { current_brand = it->first; max = it->second; } } - #endif +#endif if (max == 0) { - current_brand = "Unknown"; + return "Unknown"; } -#endif // goofy ass C++11 and C++14 linker error workaround #if (CPP <= 14) @@ -5815,6 +5795,9 @@ struct VM { constexpr const char* TMP_ESX = "VMware ESX"; constexpr const char* TMP_GSX = "VMware GSX"; constexpr const char* TMP_WORKSTATION = "VMware Workstation"; + + constexpr const char* TMP_VPC = "Virtual PC"; + constexpr const char* TMP_HYPERV = "Microsoft Hyper-V"; #else constexpr const char* TMP_QEMU = VM::QEMU; constexpr const char* TMP_KVM = VM::KVM; @@ -5824,17 +5807,22 @@ struct VM { constexpr const char* TMP_ESX = VM::VMWARE_ESX; constexpr const char* TMP_GSX = VM::VMWARE_GSX; constexpr const char* TMP_WORKSTATION = VM::VMWARE_WORKSTATION; + + constexpr const char* TMP_VPC = VM::VPC; + constexpr const char* TMP_HYPERV = VM::HYPERV; #endif - #define brands core::brand_scoreboard if ( brands.at(TMP_QEMU) > 0 && brands.at(TMP_KVM) > 0 ) { current_brand = "QEMU+KVM"; - } - - if (brands.at(TMP_VMWARE) > 0) { + } else if ( + brands.at(TMP_VPC) > 0 && + brands.at(TMP_HYPERV) > 0 + ) { + current_brand = "Microsoft Virtual PC/Hyper-V"; + } else if (brands.at(TMP_VMWARE) > 0) { if (brands.at(TMP_EXPRESS) > 0) { current_brand = TMP_EXPRESS; } else if (brands.at(TMP_ESX) > 0) { @@ -5844,13 +5832,30 @@ struct VM { } else if (brands.at(TMP_WORKSTATION) > 0) { current_brand = TMP_WORKSTATION; } - } + } else if (is_multiple) { + std::vector potential_brands; -#ifdef __VMAWARE_DEBUG__ - for (const auto p : brands) { - debug("scoreboard: ", (int)p.second, " : ", p.first); + for (auto it = brands.cbegin(); it != brands.cend(); ++it) { + const u8 points = it->second; + const std::string brand = it->first; + + if (points > 0) { + potential_brands.push_back(brand); + } + } + + std::stringstream ss; + u8 i = 1; + + ss << potential_brands.front(); + + for (; i < potential_brands.size(); i++) { + ss << " or "; + ss << potential_brands.at(i); + } + + return ss.str(); } -#endif return current_brand; } @@ -5989,6 +5994,7 @@ VM::flagset VM::DEFAULT = []() -> flagset { tmp.flip(NO_MEMO); tmp.flip(CURSOR); tmp.flip(WIN_HYPERV_DEFAULT); + tmp.flip(MULTIPLE); return tmp; }(); @@ -6079,7 +6085,7 @@ const std::map VM::core::table = { { VM::HYPERV_REG, { 80, VM::hyperv_registry }}, { VM::BIOS_SERIAL, { 60, VM::bios_serial }}, { VM::VBOX_FOLDERS, { 45, VM::vbox_shared_folders }}, - { VM::VBOX_MSSMBIOS, { 75, VM::vbox_mssmbios }}, + { VM::MSSMBIOS, { 75, VM::mssmbios }}, { VM::MAC_MEMSIZE, { 30, VM::hw_memsize }}, { VM::MAC_IOKIT, { 80, VM::io_kit }}, { VM::IOREG_GREP, { 75, VM::ioreg_grep }}, @@ -6103,11 +6109,11 @@ const std::map VM::core::table = { { VM::VMWARE_IOPORTS, { 70, VM::vmware_ioports }}, { VM::VMWARE_SCSI, { 40, VM::vmware_scsi }}, { VM::VMWARE_DMESG, { 65, VM::vmware_dmesg }}, - { VM::VMWARE_EMULATION, { 20, VM::vmware_emul }}, { VM::VMWARE_STR, { 35, VM::vmware_str }}, { VM::VMWARE_BACKDOOR, { 100, VM::vmware_backdoor }}, { VM::VMWARE_PORT_MEM, { 85, VM::vmware_port_memory }}, - { VM::SMSW, { 30, VM::smsw }} + { VM::SMSW, { 30, VM::smsw }}, + { VM::MUTEX, { 85, VM::mutex }} // __TABLE_LABEL, add your technique above // { VM::FUNCTION, { POINTS, FUNCTION_POINTER }}