diff --git a/docs/documentation.md b/docs/documentation.md index 5a07545..730482a 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -61,7 +61,7 @@ int main() { # `VM::check()` This takes a single flag argument and returns a `bool`. It's essentially the same as `VM::detect()` but it doesn't have a scoring system. It only returns the technique's effective output. The reason why this exists is because it allows end-users to have fine-grained control over what is being executed and what isn't. -`VM::detect()` is meant for a range of techniques to be evaluated in the bigger picture with weights and biases in its scoring system, while `VM::check()` is meant for a single technique to be evaluated without any weighted points or anything extra. It just gives you what the technique has found on its own. For example: +`VM::detect()` is meant for a range of techniques to be evaluated in the bigger picture with weights and biases in its scoring system, while `VM::check()` is meant for a single technique to be evaluated without any points or anything extra. It just gives you what the technique has found on its own. For example: ```cpp if (VM::check(VM::VMID)) { @@ -118,10 +118,10 @@ VMAware provides a convenient way to not only check for VMs, but also have the f | `VM::VBOX_NETWORK` | Check VBox network provider string | Windows | 70% | | `VM::COMPUTER_NAME` | Check for computer name string | Windows | 40% | | `VM::MEMORY` | Check if memory space is far too low for a physical machine | Windows | 35% | - +| `VM::VM_PROCESSES` | Check for any VM processes that are active | Windows | 30% | # Non-technique flags | Flag | Description | |------|-------------| -| `VM::ALL` | This will enable all the flags technique flags, including the cursor check. | +| `VM::ALL` | This will enable all the technique flags, including the cursor check. | | `VM::NO_MEMO` | This will disable memoization, meaning the result will not be fetched through a previous computation of the VM::detect function. Not sure why you'd need this, but it will take a performance hit if enabled. | diff --git a/src/cli.cpp b/src/cli.cpp index a985471..71728da 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -95,6 +95,11 @@ int main(int argc, char* argv[]) { checker(VM::HWMODEL, "hw.model"); checker(VM::DISK_SIZE, "disk size"); checker(VM::VBOX_DEFAULT, "VBox default specs"); + checker(VM::VBOX_NETWORK, "VBox network provider match"); + checker(VM::COMPUTER_NAME, "computer name"); + checker(VM::HOSTNAME, "hostname"); + checker(VM::MEMORY, "low memory space"); + checker(VM::VM_PROCESSES, "VM processes"); std::printf("\n"); std::cout << "VM brand: " << (std::string(VM::brand()) == "Unknown" ? red : green) << VM::brand() << ansi_exit << "\n\n"; diff --git a/src/vmaware.hpp b/src/vmaware.hpp index dae9043..a8d24fd 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -205,7 +205,8 @@ struct VM { WINE = "Wine", VAPPLE = "Virtual Apple", VPC = "Virtual PC", - ANUBIS = "Anubis"; + ANUBIS = "Anubis", + JOEBOX = "JoeBox"; // VM scoreboard table specifically for VM::brand() static inline std::map scoreboard { @@ -226,8 +227,8 @@ struct VM { { WINE, 0 }, { VAPPLE, 0 }, { VPC, 0 }, - { ANUBIS, 0 } - + { ANUBIS, 0 }, + { JOEBOX, 0 } }; // check if cpuid is supported @@ -302,8 +303,8 @@ struct VM { #if (!LINUX) return false; #else - uid_t uid = getuid(); - uid_t euid = geteuid(); + const uid_t uid = getuid(); + const uid_t euid = geteuid(); return ( (uid != euid) || @@ -460,8 +461,8 @@ struct VM { GlobalMemoryStatusEx(&statex); // calls NtQuerySystemInformation return statex.ullTotalPhys; #elif (LINUX) - i64 pages = sysconf(_SC_PHYS_PAGES); - i64 page_size = sysconf(_SC_PAGE_SIZE); + const i64 pages = sysconf(_SC_PHYS_PAGES); + const i64 page_size = sysconf(_SC_PAGE_SIZE); return (pages * page_size); #elif (APPLE) i32 mib[2] = { CTL_HW, HW_MEMSIZE }; @@ -548,6 +549,7 @@ struct VM { COMPUTER_NAME = 1ULL << 33, HOSTNAME = 1ULL << 34, MEMORY = 1ULL << 35, + VM_PROCESSES = 1ULL << 36, // settings NO_MEMO = 1ULL << 63, @@ -2098,6 +2100,7 @@ struct VM { /** * @brief Check if memory is too low * @author Al-Khaser project + * @category x86? */ [[nodiscard]] static bool low_memory_space() try { if (disabled(MEMORY)) { @@ -2110,16 +2113,90 @@ struct VM { } catch (...) { return false; } + /** + * @brief Check for any VM processes that are active + * @category Windows + */ + [[nodiscard]] static bool vm_processes() try { + if (disabled(VM_PROCESSES)) { + return false; + } + + #if (!MSVC) + return false; + #else + auto check_proc = [](const char* proc) -> bool { + HANDLE hSnapshot; + PROCESSENTRY32 pe = {}; + + pe.dwSize = sizeof(pe); + bool present = false; + hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + + if (hSnapshot == INVALID_HANDLE_VALUE) { + return false; + } + + if (Process32First(hSnapshot, &pe)) { + do { + if (!StrCmpI(pe.szExeFile, proc_name.c_str())) { + present = true; + break; + } + } while (Process32Next(hSnapshot, &pe)); + } + + CloseHandle(hSnapshot); + + return present; + }; + + if (check_proc("joeboxserver.exe") || check_proc("joeboxcontrol.exe")) { + return add(JOEBOX); + } + + if (check_proc("prl_cc.exe") || check_proc("prl_tools.exe")) { + return add(PARALLELS); + } + + if (check_proc("vboxservice.exe") || check_proc("vboxtray.exe")) { + return add(VBOX); + } + + if (check_proc("vmsrvc.exe") || check_proc("vmusrvc.exe")) { + return add(VPC); + } + + if ( + check_proc("vmtoolsd.exe") || + check_proc("vmacthlp.exe") || + check_proc("vmwaretray.exe") || + check_proc("vmwareuser.exe") || + check_proc("vmware.exe") || + check_proc("vmount2.exe") + ) { + return add(VMWARE); + } + + if (check_proc("xenservice.exe") || check_proc("xsvc_depriv.exe")) { + return add(XEN); + } + + return false; + #endif + } catch (...) { return false; } + + // __LABEL (ignore this, it's just a label so I can easily teleport to this line on my IDE with CTRL+F) - struct data { + struct technique { u8 points; bool(*ptr)(); // function pointer }; // the points are debatable, but I think it's fine how it is. Feel free to disagree. - static inline std::map table = { + static inline std::map table = { { VM::VMID, { 100, vmid }}, { VM::BRAND, { 50, cpu_brand }}, { VM::HYPERV_BIT, { 95, cpuid_hyperv }}, @@ -2155,7 +2232,8 @@ struct VM { { VM::VBOX_NETWORK, { 70, vbox_network_share }}, { VM::COMPUTER_NAME, { 40, computer_name_match }}, { VM::HOSTNAME, { 25, hostname_match }}, - { VM::MEMORY, { 35, low_memory_space }} + { VM::MEMORY, { 35, low_memory_space }}, + { VM::VM_PROCESSES, { 30, vm_processes }} // { VM::, { , }} // ^ line template for personal use @@ -2198,7 +2276,7 @@ struct VM { throw std::invalid_argument("Flag argument must be a technique flag and not a settings flag, consult the documentation's flag list"); } - // count should only have a single flag at this point + // count should only have a single flag at this stage assert(count == 1); // temporarily enable all flags so that every technique is enabled @@ -2213,7 +2291,7 @@ struct VM { throw std::invalid_argument("Flag is not known, consult the documentation's flag list"); } - const data &pair = it->second; + const technique &pair = it->second; result = pair.ptr(); VM::flags = tmp_flags; @@ -2255,7 +2333,10 @@ struct VM { * execution of VM::detect(). This can save around * 5~10x speed depending on the circumstances. */ - if (disabled(NO_MEMO) && (memo.find(true) != memo.end())) { + if ( + disabled(NO_MEMO) && \ + memo.find(true) != memo.end() + ) { debug("memoization: returned cached result in detect()"); return memo[true].first; } @@ -2267,13 +2348,13 @@ struct VM { u8 points = 0; for (auto it = table.cbegin(); it != table.cend(); ++it) { - const data &pair = it->second; + const technique &pair = it->second; if (pair.ptr()) { points += pair.points; }; } - // arbitrary threshold score + // threshold score const bool result = (points >= 100); sv current_brand = ""; @@ -2293,11 +2374,13 @@ struct VM { ); if (it != scoreboard.end()) { - if (std::none_of(scoreboard.cbegin(), scoreboard.cend(), - [](const auto &pair) { - return pair.second; - } - )) { + if ( + std::none_of(scoreboard.cbegin(), scoreboard.cend(), + [](const auto &pair) { + return pair.second; + } + ) + ) { current_brand = "Unknown"; } else { current_brand = it->first;