From e6d7b11647df0f190623cc759253866bb8bc9b55 Mon Sep 17 00:00:00 2001 From: Existential-Kernel Date: Mon, 18 Sep 2023 05:19:45 +0100 Subject: [PATCH] added hwmodel and updated readme --- .gitignore | 3 +- README.md | 45 ++++++++++++++----------- TODO.md | 1 + docs/documentation.md | 1 + src/cli.cpp | 2 +- src/vmaware.hpp | 77 ++++++++++++++++++++++++++++++++++++------- 6 files changed, 96 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 6416ccf..3038268 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,5 @@ src/vmtest.cpp resources/ archive/ .vscode/ -build/ \ No newline at end of file +build/ +milestones.md \ No newline at end of file diff --git a/README.md b/README.md index fde61fb..0fd7405 100644 --- a/README.md +++ b/README.md @@ -17,42 +17,41 @@ The library is: - Cross-platform (to an extent) - Header-only - Available with C++11 and above -- Able to detect VMware, VirtualBox, QEMU, KVM, Parallels, and much more! +- Able to detect VMware, VirtualBox, QEMU, KVM, Parallels, and much more - Able to detect semi-VM technologies like hypervisors, docker, and wine - Able to determine the VM brand -- Incredibly fast (takes around 1~5 milliseconds) - Memoized, meaning past results are cached and retrieved if ran again for performance benefits - - - -**IMPORTANT:** The library is currently a beta, so more improvements and cross-compatibility fixes are planned (especially for Windows which I'm currently working on fixing). I don't recommend using this for any serious projects for now. +**IMPORTANT:** The library is currently a beta, so more improvements and cross-compatibility fixes are planned (especially for Windows which I'm currently working on fixing). Although the project is improving on a daily basis, I don't recommend using this for any serious projects for now. - - - -# Example ๐Ÿงช +## Example ๐Ÿงช ```cpp #include "vmaware.hpp" #include int main() { if (VM::detect()) { - std::cout << "Virtual machine detected!\n"; - std::cout << "VM name: " << VM::brand() << "\n"; + std::cout << "Virtual machine detected!" << std::endl; + std::cout << "VM name: " << VM::brand() << std::endl; } else { - std::cout << "Running in baremetal\n"; + std::cout << "Running in baremetal" << std::endl; } } ``` -# CLI tool ๐Ÿ”ง +## CLI tool ๐Ÿ”ง This project also provides a tiny, but handy CLI tool utilising the full potential of what the library can do. -# Installation ๐Ÿ“ฅ +## Installation ๐Ÿ“ฅ To install the library, simply download or copy and paste the [vmaware.hpp](src/vmaware.hpp) file to your project. No CMake or build frameworks are necessary, it's literally that simple. However, if you want the full project (globally accessible headers with and the CLI tool), follow these commands: @@ -67,29 +66,37 @@ sudo make install > NOTE: I'm most likely going to change my username in the future. If the github link doesn't exist, search for the VMAware project and you should find it. -# Documentation ๐Ÿ“’ +## Documentation ๐Ÿ“’ You can view the full docs [here](docs/documentation.md). Trust me, it's not too intimidating -# Q&A โ“ +## Q&A โ“ - Who is this library for? -> It's designed for anticheat developers, security researchers, VM engineers, and pretty much anybody who needs a practical and rock-solid VM detection mechanism in their project. For example, if you're a gamer developer and you want to prevent exploit developers probing the game in a VM or anybody attempting a ban evasion, this is a suitable project for those use cases. +> It's designed for security researchers, VM engineers, anticheat developers*, and pretty much anybody who needs a practical and rock-solid VM detection mechanism in their project. For example, if you're making a VM and you're testing the effectiveness of concealing itself, or if you're a malware analyst and you want to check if your VM environment is good enough. - Why another VM detection project? -> There's already loads of projects that have the same goal such as [InviZzzible](https://github.com/CheckPointSW/InviZzzible), [pafish](https://github.com/a0rtega/pafish) and [Al-Khaser](https://github.com/LordNoteworthy/al-khaser). But the difference between the aforementioned projects is that they have little to no support with non-Windows systems. On top of this, I wanted the VM detection techniques to be accessible programmatically for everybody to find something useful out of it rather than providing just a CLI tool like the projects above. +> There's already loads of projects that have the same goal such as [InviZzzible](https://github.com/CheckPointSW/InviZzzible), [pafish](https://github.com/a0rtega/pafish) and [Al-Khaser](https://github.com/LordNoteworthy/al-khaser). But the difference between the aforementioned projects is that they have little to no support with non-Windows systems. On top of this, I wanted the core detection techniques to be accessible programmatically for everybody to get something useful out of it rather than providing just a CLI tool like the projects above. + +- Is it possible to spoof the result? +> Yes. There are some techniques that are trivially spoofable, and there's nothing the library can do about it whether it's a false negative or even a false positive. This is a problem that every VM detection project is facing, which is why the library is trying to test every technique possible to get the best result based on the environment it's running under. - Can I use this for malware? -> This project is not soliciting the development of malware for any malicious purpose. Even if you intend to use it that way, it'll most likely be flagged by antiviruses anyway. +> This project is not soliciting the development of malware for any malicious intentions. Even if you intend to use it that way, it'll most likely be flagged by antiviruses anyway. + +- If it's designed for anti-cheat, why is it GPL? +> I used/modified a few GPL-3.0 code from other projects. Works that are derived from that license must use the same license, so I had no choice but to use it. An open-source anti-cheat sounds like a bad idea, and frankly it is for a few reasons. Although it's possible, this isn't a good library for anti-cheats in that regard even if it can be used for that purpose. On the other hand, it can prevent exploit developers probing the game in a VM or anybody attempting a ban evasion, which is worth a mention. - When will a 1.0 be available? -> Pretty soon, maybe around a week or 2 (I just started university a few days ago, so I can't guarantee anything) +> Pretty soon, maybe around November (I just started university a few days ago, so I can't guarantee anything) + +## Issues and pull requests +If you have any suggestions, ideas, or any sort of contribution, feel free to ask! I'll be more than happy to discuss. If you want to personally say something for whatever reason, my discord is `kr.nl` -# Issues and pull requests -If you have any suggestions, ideas, or any sort of contribution, feel free to ask! I'll be more than happy to discuss. If you found this project useful, a star would be appreciated :) +If you found this project useful, a star would be appreciated :) -# Credits โœ’๏ธ +## Credits โœ’๏ธ - [Check Point Research](https://research.checkpoint.com/) - [Unprotect Project](https://unprotect.it/) - [Al-Khaser](https://github.com/LordNoteworthy/al-khaser) @@ -97,7 +104,7 @@ If you have any suggestions, ideas, or any sort of contribution, feel free to as - [Matteo Malvica](https://www.matteomalvica.com) -# Legal ๐Ÿ“œ +## Legal ๐Ÿ“œ I am not responsible nor liable for any damage you cause through any malicious usage of this project. License: GPL-3.0 \ No newline at end of file diff --git a/TODO.md b/TODO.md index 34e74d7..1f789d4 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,6 @@ - revise sidt check - analyse the UUID check technique's efficiency +- create a technique table so i don't have to manually add them for VM::detect() and VM::check() - ~~make a flagcheck function~~ - ~~create a standard cpuid function (replace __cpuidex bc wine)~~ diff --git a/docs/documentation.md b/docs/documentation.md index 546054a..be0c87b 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -111,6 +111,7 @@ VMAware provides a convenient way to not only check for VMs, but also have the f | 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 | +| Check hwmodel | Check if the sysctl for the hwmodel does not contain the "Mac" string | `VM::HWMODEL` | MacOS | # Non-technique flags | Flag | Description | diff --git a/src/cli.cpp b/src/cli.cpp index 3f83a69..f8dafc7 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -26,7 +26,7 @@ R"(Usage: } void version(void) { - std::cout << "v" << ver << " (" << date << ")\n\n" << + std::cout << "vmaware " << "v" << ver << " (" << date << ")\n\n" << "Derived project of VMAware library at https://github.com/kernelwernel/VMAware" "License GPLv3+: GNU GPL version 3 or later .\n" << "This is free software: you are free to change and redistribute it.\n" << diff --git a/src/vmaware.hpp b/src/vmaware.hpp index a72a4c5..b601923 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -4,7 +4,7 @@ * โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ–ˆโ–ˆโ–ˆโ–ˆโ•”โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ•— โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— * โ•šโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ• * โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ–ˆโ–ˆโ•‘ โ•šโ•โ• โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ•”โ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— - * โ•šโ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•šโ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• v1.0 + * โ•šโ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•šโ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• v0.1 * * A C++ VM detection library * @@ -82,8 +82,8 @@ #if (MSVC) - #include #include + #include #include #include #include @@ -352,7 +352,7 @@ struct VM { VM(VM&&) = delete; // Delete move constructor static constexpr u64 - VMID = 1 << 0, + VMID = 1 << 0, BRAND = 1 << 1, HYPERV_BIT = 1 << 2, CPUID_0x4 = 1 << 3, @@ -385,6 +385,7 @@ struct VM { WINE_CHECK = 1ULL << 47, BOOT = 1ULL << 48, VM_FILES = 1ULL << 49, + HWMODEL = 1ULL << 50, // settings NO_MEMO = 1ULL << 63, @@ -1643,7 +1644,7 @@ struct VM { #if (!MSVC) return false; #else - if (disabled(WINE)) { + if (disabled(WINE_CHECK)) { #ifdef __VMAWARE_DEBUG__ debug("WINE: ", "precondition return called"); #endif @@ -1676,12 +1677,15 @@ struct VM { } #if (MSVC) + // doesn't work for some reason, fix this whenever i have time + /* SYSTEM_TIME_OF_DAY_INFORMATION SysTimeInfo; LARGE_INTEGER LastBootTime; NtQuerySystemInformation(SystemTimeOfDayInformation, &SysTimeInfo, sizeof(SysTimeInfo), 0); LastBootTime = wmi_Get_LastBootTime(); return ((wmi_LastBootTime.QuadPart - SysTimeInfo.BootTime.QuadPart) / 10000000 != 0); // 0 seconds + */ #elif (LINUX) // TODO: finish this shit tomorrow #endif @@ -1764,8 +1768,55 @@ struct VM { } catch (...) { return false; } + /** + * @brief Check for sysctl hardware model + * @author MacRansom ransomware + * @todo TEST IF THIS WORKS + * @category MacOS + */ + [[nodiscard]] static bool hwmodel() try { + #if (!APPLE) + return false; + #else + if (disabled(HWMODEL)) { + #ifdef __VMAWARE_DEBUG__ + debug("HWMODEL: ", "precondition return called"); + #endif + return false; + } + + auto result = sys_result("sysctl -n hw.model"); - // LABEL (ignore this line, it's just a label so I can easily teleport to this line on my IDE with CTRL+F) + std::smatch match; + + if (result == nullptr) { + #ifdef __VMAWARE_DEBUG__ + debug("HWMODEL: ", "null result received"); + #endif + return false; + } + + #ifdef __VMAWARE_DEBUG__ + debug("HWMODEL: ", "output = ", *result); + #endif + + // if string contains "Mac" anywhere in the string, assume it's baremetal + if (std::regex_search(*result, match, std::regex("Mac"))) { + return false; + } + + // not sure about the other VMs, more could potentially be added + if (std::regex_search(*result, match, std::regex("VMware"))) { + return add(VMWARE); + } + + return true; + #endif + } + + + + // LABEL (ignore this, it's just a label so I can easily teleport to this line on my IDE with CTRL+F) public: /** @@ -1788,6 +1839,10 @@ struct VM { } #endif + if (p_flags == ALL) { + throw std::invalid_argument("Flag argument cannot be set to VM::ALL, consult the documentation's flag list"); + } + if (count > 1) { throw std::invalid_argument("Flag argument must only contain a single option, consult the documentation's flag list"); } @@ -1839,6 +1894,7 @@ struct VM { case VM::WINE_CHECK: result = wine(); break; case VM::BOOT: result = boot_time(); break; case VM::VM_FILES: result = vm_files(); break; + case VM::HWMODEL: result = hwmodel(); break; default: throw std::invalid_argument("Unknown flag provided for VM::check() function"); } @@ -1917,20 +1973,17 @@ struct VM { if (sunbelt_check()) { points += 1; } if (wine()) { points += 3.5; } if (boot_time()) { points += 0.5; } + if (vm_files()) { points += 4; } + if (hwmodel()) { points += 2.5; } - /** - * you can change this threshold score to a maximum - * of something like 10~14 if you want to be extremely - * sure, but this can risk the result to be a false - * negative if the detection bar is far too high. - */ + // arbitrary threshold score const bool result = (points >= 6.5); sv current_brand = ""; #ifdef __VMAWARE_DEBUG__ for (const auto p : scoreboard) { - std::cout << "\n" << (int)p.second << " : " << p.first; + debug("scoreboard: ", (int)p.second, " : ", p.first); } #endif