diff --git a/.github/workflows/msvc.yml b/.github/workflows/msvc.yml deleted file mode 100644 index e3a25fe..0000000 --- a/.github/workflows/msvc.yml +++ /dev/null @@ -1,66 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# -# Find more information at: -# https://github.com/microsoft/msvc-code-analysis-action - -name: Microsoft C++ Code Analysis - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - schedule: - - cron: '18 18 * * 1' - -env: - # Path to the CMake build directory. - build: '${{ github.workspace }}/build' - -permissions: - contents: read - -jobs: - analyze: - permissions: - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/upload-sarif to upload SARIF results - actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status - name: Analyze - runs-on: windows-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Configure CMake - run: cmake -B ${{ env.build }} - - # Build is not required unless generated source files are used - # - name: Build CMake - # run: cmake --build ${{ env.build }} - - - name: Initialize MSVC Code Analysis - uses: microsoft/msvc-code-analysis-action@04825f6d9e00f87422d6bf04e1a38b1f3ed60d99 - # Provide a unique ID to access the sarif output path - id: run-analysis - with: - cmakeBuildDirectory: ${{ env.build }} - # Ruleset file that will determine what checks will be run - ruleset: NativeRecommendedRules.ruleset - - # Upload SARIF file to GitHub Code Scanning Alerts - - name: Upload SARIF to GitHub - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: ${{ steps.run-analysis.outputs.sarif }} - - # Upload SARIF file as an Artifact to download and view - # - name: Upload SARIF as an Artifact - # uses: actions/upload-artifact@v3 - # with: - # name: sarif-file - # path: ${{ steps.run-analysis.outputs.sarif }} \ No newline at end of file diff --git a/TODO.md b/TODO.md index 4ab6431..34e74d7 100644 --- a/TODO.md +++ b/TODO.md @@ -1,12 +1,12 @@ -- finish the linux one FIRST - revise sidt check -- convert makefile to cmake -- maybe add github templates and other ci/cd stuff +- analyse the UUID check technique's efficiency - ~~make a flagcheck function~~ - ~~create a standard cpuid function (replace __cpuidex bc wine)~~ - ~~fix the pointer destruction error~~ +- ~~convert makefile to cmake~~ - ~~fix the inconsistent naming~~ +- ~~maybe add github templates and other ci/cd stuff~~ # distant plans diff --git a/docs/documentation.md b/docs/documentation.md index e53e2ed..546054a 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -97,7 +97,7 @@ VMAware provides a convenient way to not only check for VMs, but also have the f | Check temperature | Check for the presence of CPU temperature sensors (mostly not present in VMs) | `VM::TEMPERATURE` | Linux | | Check chassis vendor | Check if the chassis has any VM-related keywords | `VM::CVENDOR` | Linux | | Check chassis type | Check if the chassis type is valid (usually not in VMs) | `VM::CTYPE` | Linux | -| Check docker | Check if any docker-related files are present such as /.dockerenv and /.dockerinit | `VM::DOCKER` | Linux | +| Check docker | Check if any docker-related files are present such as /.dockerenv and /.dockerinit | `VM::DOCKER_CHECK` | Linux | | Check dmidecode | Get output from dmidecode tool and grep for common VM keywords | `VM::DMIDECODE` | Linux | | Check dmesg | Get output from dmesg tool and grep for common VM keywords | `VM::DMESG` | Linux | | Check HWMON | Check if HWMON is present (if not, likely a VM) | `VM::HWMON` | Linux | @@ -108,8 +108,9 @@ VMAware provides a convenient way to not only check for VMs, but also have the f | Check DLLs | Match for VM-specific DLLs | `VM::DLL` | Windows | | Check registry | Look throughout the registry for all sorts of VMs | `VM::REGISTRY` | Windows | | Check Sunbelt | Detect for Sunbelt technology | `VM::SUNBELT` | Windows | -| Check Wine | Find for a Wine-specific file | `VM::WINE` | Windows | +| Check Wine | Find for a Wine-specific file | `VM::WINE_CHECK` | Windows | | Check boot time | Analyse the OS uptime | `VM::BOOT` | Yes | +| Check VM files | Find if any VM-specific files exists | `VM::VM_FILES` | Windows | # Non-technique flags | Flag | Description | diff --git a/src/cli.cpp b/src/cli.cpp index 0dba25b..3f83a69 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -58,7 +58,7 @@ int main(int argc, char* argv[]) { checker(VM::SYSTEMD, "systemd virtualisation"); checker(VM::CVENDOR, "chassis vendor"); checker(VM::CTYPE, "chassis type"); - checker(VM::DOCKER, "Dockerenv"); + checker(VM::DOCKER_CHECK, "Dockerenv"); checker(VM::DMIDECODE, "dmidecode output"); checker(VM::DMESG, "dmesg output"); checker(VM::HWMON, "hwmon presence"); @@ -69,6 +69,9 @@ int main(int argc, char* argv[]) { checker(VM::DLL, "DLLs"); checker(VM::REGISTRY, "registry"); checker(VM::SUNBELT, "Sunbelt"); + checker(VM::WINE_CHECK, "Wine"); + checker(VM::BOOT, "boot uptime"); + checker(VM::VM_FILES, "VM files"); 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 6b9aeb6..a72a4c5 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -90,6 +90,7 @@ #include #include #include + #include #pragma comment(lib, "iphlpapi.lib") #elif (LINUX) #include @@ -177,25 +178,45 @@ struct VM { } #endif + // official aliases for VM brands. This is added to avoid accidental typos which could really fuck up the result. Also, no errors/warnings are issued if the string is invalid. + static constexpr sv + VMWARE = "VMware", + VBOX = "VirtualBox", + KVM = "KVM", + BHYVE = "bhyve", + QEMU = "QEMU", + HYPERV = "Microsoft Hyper-V", + MSXTA = "Microsoft x86-to-ARM", + PARALLELS = "Parallels", + XEN = "Xen HVM", + ACRN = "ACRN", + QNX = "QNX hypervisor", + HYBRID = "Hybrid Analysis", + SANDBOXIE = "Sandboxie", + DOCKER = "Docker", + WINE = "Wine", + VAPPLE = "Virtual Apple", + VPC = "Virtual PC"; + // VM scoreboard table specifically for VM::brand() static inline std::map scoreboard { - { "VMware", 0 }, - { "VirtualBox", 0 }, - { "KVM", 0 }, - { "bhyve", 0 }, - { "QEMU", 0 }, - { "Microsoft Hyper-V", 0 }, - { "Microsoft x86-to-ARM", 0 }, - { "Parallels", 0 }, - { "Xen HVM", 0 }, - { "ACRN", 0 }, - { "QNX hypervisor", 0 }, - { "Hybrid Analysis", 0 }, - { "Sandboxie", 0 }, - { "Docker", 0 }, - { "Wine", 0 }, - { "Virtual Apple", 0 }, - { "Virtual PC", 0 } + { VMWARE, 0 }, + { VBOX, 0 }, + { KVM, 0 }, + { BHYVE, 0 }, + { QEMU, 0 }, + { HYPERV, 0 }, + { MSXTA, 0 }, + { PARALLELS, 0 }, + { XEN, 0 }, + { ACRN, 0 }, + { QNX, 0 }, + { HYBRID, 0 }, + { SANDBOXIE, 0 }, + { DOCKER, 0 }, + { WINE, 0 }, + { VAPPLE, 0 }, + { VPC, 0 } }; // check if cpuid is supported @@ -347,7 +368,7 @@ struct VM { SYSTEMD = 1 << 11, CVENDOR = 1 << 12, CTYPE = 1 << 13, - DOCKER = 1 << 14, + DOCKER_CHECK = 1 << 14, DMIDECODE = 1 << 15, DMESG = 1 << 16, HWMON = 1 << 17, @@ -361,8 +382,9 @@ struct VM { DLL = 1ULL << 44, REGISTRY = 1ULL << 45, SUNBELT = 1ULL << 46, - WINE = 1ULL << 47, + WINE_CHECK = 1ULL << 47, BOOT = 1ULL << 48, + VM_FILES = 1ULL << 49, // settings NO_MEMO = 1ULL << 63, @@ -455,22 +477,22 @@ struct VM { const bool found = (std::find(std::begin(IDs), std::end(IDs), brand) != std::end(IDs)); if (found) { - if (brand == bhyve) { scoreboard["bhyve"]++; } - if (brand == kvm) { scoreboard["KVM"]++; } - if (brand == qemu) [[likely]] { scoreboard["QEMU"]++; } - if (brand == hyperv) { scoreboard["Microsoft Hyper-V"]++; } - if (brand == xta) { scoreboard["Microsoft x86-to-ARM"]++; } - if (brand == vmware) [[likely]] { scoreboard["VMware"]++; } - if (brand == vbox) [[likely]] { scoreboard["VirtualBox"]++; } - if (brand == parallels) { scoreboard["Parallels"]++; } - if (brand == parallels2) { scoreboard["Parallels"]++; } - if (brand == xen) { scoreboard["Xen HVM"]++; } - if (brand == acrn) { scoreboard["ACRN"]++; } - if (brand == qnx) { scoreboard["QNX hypervisor"]++; } - if (brand == virtapple) { scoreboard["Virtual Apple"]++; } + if (brand == bhyve) { return add(BHYVE); } + if (brand == kvm) { return add(KVM); } + if (brand == qemu) [[likely]] { return add(QEMU); } + if (brand == hyperv) { return add(HYPERV); } + if (brand == xta) { return add(MSXTA); } + if (brand == vmware) [[likely]] { return add(VMWARE); } + if (brand == vbox) [[likely]] { return add(VBOX); } + if (brand == parallels) { return add(PARALLELS); } + if (brand == parallels2) { return add(PARALLELS); } + if (brand == xen) { return add(XEN); } + if (brand == acrn) { return add(ACRN); } + if (brand == qnx) { return add(QNX); } + if (brand == virtapple) { return add(VAPPLE); } } - return found; + return false; #endif } catch (...) { return false; } @@ -527,7 +549,7 @@ struct VM { u8 matches = 0; for (std::size_t i = 0; i < vmkeywords.size(); i++) { - auto const regex = std::regex(vmkeywords.at(i), std::regex::icase); + const auto regex = std::regex(vmkeywords.at(i), std::regex::icase); matches += std::regex_search(brand, regex); } @@ -858,10 +880,11 @@ struct VM { #endif if (is_vm) { - scoreboard["VMware"] += 2; // extra point bc it's incredibly VMware-specific + scoreboard[VMWARE] += 2; // extra point bc it's incredibly VMware-specific + return true; } - return is_vm; + return false; #endif } catch (...) { return false; } @@ -996,7 +1019,7 @@ struct VM { }; if (compare(0x08, 0x00, 0x27)) { - return add("VirtualBox"); + return add(VBOX); } if ( @@ -1005,19 +1028,19 @@ struct VM { (compare(0x00, 0x50, 0x56)) || (compare(0x00, 0x05, 0x69)) ) { - return add("VMware"); + return add(VMWARE); } if (compare(0x00, 0x16, 0xE3)) { - return add("Xen HVM"); + return add(XEN); } if (compare(0x00, 0x1C, 0x42)) { - return add("Parallels"); + return add(PARALLELS); } if (compare(0x0A, 0x00, 0x27)) { - return add("Hybrid Analysis"); + return add(HYBRID); } return false; @@ -1105,8 +1128,8 @@ struct VM { const std::string vendor = read_file(vendor_file); // TODO: More can be definitely added, I only tried QEMU and VMware so far - if (vendor == "QEMU") { return add("QEMU"); } - if (vendor == "Oracle Corporation") { return add("VMware"); } + if (vendor == "QEMU") { return add(QEMU); } + if (vendor == "Oracle Corporation") { return add(VMWARE); } #ifdef __VMAWARE_DEBUG__ debug("CVENDOR: ", "unknown vendor = ", vendor); @@ -1160,7 +1183,7 @@ struct VM { #if (!LINUX) return false; #else - if (disabled(DOCKER)) { + if (disabled(DOCKER_CHECK)) { #ifdef __VMAWARE_DEBUG__ debug("DOCKER: ", "precondition return called"); #endif @@ -1202,11 +1225,11 @@ struct VM { #endif return false; } else if (*result == "QEMU") { - return add("QEMU"); + return add(QEMU); } else if (*result == "VirtualBox") { - return add("VirtualBox"); + return add(VBOX); } else if (*result == "KVM") { - return add("KVM"); + return add(KVM); } else if (std::atoi(result->c_str()) >= 1) { return true; } else { @@ -1247,9 +1270,9 @@ struct VM { if (*result == "" || result == nullptr) { return false; } else if (*result == "KVM") { - return add("KVM"); + return add(KVM); } else if (*result == "QEMU") { - return add("QEMU"); + return add(QEMU); } else if (std::atoi(result->c_str())) { return true; } else { @@ -1539,8 +1562,7 @@ struct VM { if (handle != INVALID_HANDLE_VALUE) { CloseHandle(handle); - scoreboard["VirtualBox"]++; - return true; + return add(VBOX); } return false; @@ -1574,7 +1596,7 @@ struct VM { bool result = (RegOpenKeyEx(TEXT("SOFTWARE\\VMware, Inc.\\VMware Tools"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS); if (result == true) { - scoreboard["VMware"]++; + return add(VMWARE); } return result; @@ -1659,12 +1681,92 @@ struct VM { NtQuerySystemInformation(SystemTimeOfDayInformation, &SysTimeInfo, sizeof(SysTimeInfo), 0); LastBootTime = wmi_Get_LastBootTime(); - return (wmi_LastBootTime.QuadPart - SysTimeInfo.BootTime.QuadPart) / 10000000 != 0; // 0 seconds + return ((wmi_LastBootTime.QuadPart - SysTimeInfo.BootTime.QuadPart) / 10000000 != 0); // 0 seconds #elif (LINUX) // TODO: finish this shit tomorrow #endif + + return false; + } catch (...) { return false; } + + + /** + * @brief Find for VMware and VBox specific files + * @category Windows + */ + [[nodiscard]] static bool vm_files() try { + #if (!MSVC) + return false; + #else + if (disabled(VM_FILES)) { + #ifdef __VMAWARE_DEBUG__ + debug("VMFILES: ", "precondition return called"); + #endif + return false; + } + + // points + u8 vbox = 0; + u8 vmware = 0; + + constexpr std::array files = { + // VMware + "C:\\windows\\System32\\Drivers\\Vmmouse.sys", + "C:\\windows\\System32\\Drivers\\vm3dgl.dll", + "C:\\windows\\System32\\Drivers\\vmdum.dll", + "C:\\windows\\System32\\Drivers\\VmGuestLibJava.dll", + "C:\\windows\\System32\\Drivers\\vm3dver.dll", + "C:\\windows\\System32\\Drivers\\vmtray.dll", + "C:\\windows\\System32\\Drivers\\VMToolsHook.dll", + "C:\\windows\\System32\\Drivers\\vmGuestLib.dll", + "C:\\windows\\System32\\Drivers\\vmhgfs.dll", + "C:\\windows\\System32\\Driversvmhgfs.dll", + + // VBox + "C:\\windows\\System32\\Drivers\\VBoxMouse.sys", + "C:\\windows\\System32\\Drivers\\VBoxGuest.sys", + "C:\\windows\\System32\\Drivers\\VBoxSF.sys", + "C:\\windows\\System32\\Drivers\\VBoxVideo.sys", + "C:\\windows\\System32\\vboxoglpackspu.dll", + "C:\\windows\\System32\\vboxoglpassthroughspu.dll", + "C:\\windows\\System32\\vboxservice.exe", + "C:\\windows\\System32\\vboxoglcrutil.dll", + "C:\\windows\\System32\\vboxdisp.dll", + "C:\\windows\\System32\\vboxhook.dll", + "C:\\windows\\System32\\vboxmrxnp.dll", + "C:\\windows\\System32\\vboxogl.dll", + "C:\\windows\\System32\\vboxtray.exe", + "C:\\windows\\System32\\VBoxControl.exe", + "C:\\windows\\System32\\vboxoglerrorspu.dll", + "C:\\windows\\System32\\vboxoglfeedbackspu.dll", + } + + for (const sv file : files) { + if (exists(file)) { + const auto regex = std::regex(file, std::regex::icase); + + if (std::regex_search("vbox", regex)) { + vbox++; + } else { + vmware++; + } + } + } + + if (vbox > vmware) { + return add(VBOX); + } else if (vmware > vbox) { + return add(VMWARE); + } + + return false; + #endif } catch (...) { return false; } + + + // LABEL (ignore this line, it's just a label so I can easily teleport to this line on my IDE with CTRL+F) + public: /** * @brief Check for a specific technique based on flag argument @@ -1680,13 +1782,10 @@ struct VM { #elif (CPP >= 14) count = std::__popcount(p_flags); #else - { // compiler will optimise this with the x86 popcnt instruction (I hope) - u64 tmp = p_flags; - for (; tmp != 0; count++) { + for (u64 tmp = p_flags; tmp != 0; count++) { tmp = (tmp & (tmp - 1)); } - } #endif if (count > 1) { @@ -1719,9 +1818,10 @@ struct VM { case VM::SIDT5: result = sidt5(); break; case VM::SIDT: result = sidt_check(); break; case VM::TEMPERATURE: result = temperature(); break; + case VM::SYSTEMD: result = systemd_virt(); break; case VM::CVENDOR: result = chassis_vendor(); break; case VM::CTYPE: result = chassis_type(); break; - case VM::DOCKER: result = dockerenv(); break; + case VM::DOCKER_CHECK: result = dockerenv(); break; case VM::DMIDECODE: result = dmidecode(); break; case VM::DMESG: result = dmesg(); break; case VM::HWMON: result = hwmon(); break; @@ -1736,8 +1836,10 @@ struct VM { case VM::REGISTRY: result = registry_key(); break; case VM::SUNBELT: result = sunbelt_check(); break; case VM::THREADCOUNT: result = thread_count(); break; - case VM::WINE: result = wine(); break; + case VM::WINE_CHECK: result = wine(); break; case VM::BOOT: result = boot_time(); break; + case VM::VM_FILES: result = vm_files(); break; + default: throw std::invalid_argument("Unknown flag provided for VM::check() function"); } VM::flags = tmp_flags; @@ -1826,11 +1928,11 @@ struct VM { sv current_brand = ""; -/* (left for debug stuff) - for (const auto p : scoreboard) { - std::cout << "\n" << (int)p.second << " : " << p.first; - } -*/ + #ifdef __VMAWARE_DEBUG__ + for (const auto p : scoreboard) { + std::cout << "\n" << (int)p.second << " : " << p.first; + } + #endif // fetch the brand with the most points in the scoreboard #if (CPP >= 20) diff --git a/src/vmtest.cpp b/src/vmtest.cpp index 54a96c3..1bf59ca 100644 --- a/src/vmtest.cpp +++ b/src/vmtest.cpp @@ -2,10 +2,6 @@ #include int main(void) { - - //bool lol = VM::detect(); - std::cout << VM::brand() << "\n"; - return 0; } \ No newline at end of file