Skip to content

Dev #315

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 5, 2025
Merged

Dev #315

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
| `vmaware.hpp` | Official and original library header in GPL-3.0, most likely what you're looking for. |
| `vmaware_MIT.hpp` | Same as above but in MIT. But this removes 7 techniques out of 118 |

<br>

> [!IMPORTANT]
> The main branch is much more updated with features that haven't been added yet to the latest release. However, they are experimental.
> If you want something far more stable, it's highly recommended to use the ones in the release section instead.
> If you want something far more stable, it's highly recommended to use the ones in the release section instead.
>
> On the other hand, testing the main branch version is advised so that feedback can be given back to make the library better.
59 changes: 30 additions & 29 deletions src/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,18 @@

#if (defined(__GNUC__) || defined(__linux__))
#include <unistd.h>
#define LINUX 1
#define CLI_LINUX 1
#else
#define LINUX 0
#define CLI_LINUX 0
#endif


#if (defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__))
#define WINDOWS 1
#define CLI_WINDOWS 1
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#define WINDOWS 0
#define CLI_WINDOWS 0
#endif

#if (_MSC_VER)
Expand Down Expand Up @@ -102,9 +103,9 @@ std::string not_detected = ("[" + red + "NOT DETECTED" + ansi_exit + "]");
std::string no_support = ("[ " + grey + "NO SUPPORT" + ansi_exit + " ]");
std::string no_perms = ("[" + grey + " NO PERMS " + ansi_exit + "]");
std::string note = ("[ NOTE ]");
std::string disabled = ("[" + red + " DISABLED " + ansi_exit + "]");
std::string disabled = ("[" + grey + " DISABLED " + ansi_exit + "]");

#if (WINDOWS)
#if (CLI_WINDOWS)
class win_ansi_enabler_t
{
public:
Expand Down Expand Up @@ -281,7 +282,7 @@ nsjail
}


#if (LINUX)
#if (CLI_LINUX)
bool is_admin() {
const uid_t uid = getuid();
const uid_t euid = geteuid();
Expand All @@ -297,7 +298,7 @@ bool is_admin() {


bool are_perms_required(const VM::enum_flags flag) {
#if (LINUX)
#if (CLI_LINUX)
if (is_admin()) {
return false;
}
Expand Down Expand Up @@ -508,10 +509,10 @@ bool is_unsupported(VM::enum_flags flag) {


#if __cplusplus >= 201703L
if constexpr (LINUX) {
if constexpr (CLI_LINUX) {
return linux_techniques(flag);
}
else if constexpr (WINDOWS) {
else if constexpr (CLI_WINDOWS) {
return windows_techniques(flag);
}
else if constexpr (APPLE) {
Expand All @@ -521,11 +522,11 @@ bool is_unsupported(VM::enum_flags flag) {
return true;
}
#else
#if LINUX
#if (CLI_LINUX)
return linux_techniques(flag);
#elif WINDOWS
#elif (CLI_WINDOWS)
return windows_techniques(flag);
#elif APPLE
#elif (APPLE)
return macos_techniques(flag);
#else
return true;
Expand Down Expand Up @@ -634,7 +635,7 @@ std::string vm_description(const std::string& vm_brand) {
{ brands::AZURE_HYPERV, "Azure Hyper-V is Microsoft's cloud-optimized hypervisor variant powering Azure VMs. Implements Azure-specific virtual devices like NVMe Accelerated Networking and vTPMs. Supports nested virtualization for running Hyper-V/containers within Azure VMs, enabling cloud-based CI/CD pipelines and dev/test environments." },
{ brands::NANOVISOR, "NanoVisor is a Hyper-V modification serving as the host OS of Xbox's devices: the Xbox System Software. It contains 2 partitions: the \"Exclusive\" partition is a custom VM for games, while the other partition, called the \"Shared\" partition is a custom VM for running multiple apps including the OS itself. The OS was based on Windows 8 Core at the Xbox One launch in 2013." },
{ brands::SIMPLEVISOR, "SimpleVisor is a minimalist Intel VT-x hypervisor by Alex Ionescu for Windows/Linux research. Demonstrates EPT-based memory isolation and hypercall handling. Used to study VM escapes and hypervisor rootkits, with hooks for intercepting CR3 changes and MSR accesses." },
{ brands::HYPERV_ARTIFACT, "The CLI detected Hyper-V operating as a Type 1 hypervisor, not as a guest virtual machine. Althought your hardware/firmware signatures match Microsoft's Hyper-V architecture, we determined that you're running on baremetal, with the help of our \"Hyper-X\" mechanism that differentiates between the root partition (host OS) and guest VM environments. This prevents false positives, as Windows sometimes runs under Hyper-V (type 1) hypervisor." },
{ brands::HYPERV_ARTIFACT, "The CLI detected Hyper-V operating as a Type 1 hypervisor, not as a guest virtual machine. Although your hardware/firmware signatures match Microsoft's Hyper-V architecture, we determined that you're running on baremetal, with the help of our \"Hyper-X\" mechanism that differentiates between the root partition (host OS) and guest VM environments. This prevents false positives, as Windows sometimes runs under Hyper-V (type 1) hypervisor." },
{ brands::UML, "User-Mode Linux (UML) allows running Linux kernels as user-space processes using ptrace-based virtualization. Primarily used for kernel debugging and network namespace testing. Offers lightweight isolation without hardware acceleration, but requires host/guest kernel version matching for stable operation." },
{ brands::POWERVM, "IBM PowerVM is a type 1 hypervisor for POWER9/10 systems, supporting Live Partition Mobility and Shared Processor Pools. Implements VIOS (Virtual I/O Server) for storage/networking virtualization, enabling concurrent AIX, IBM i, and Linux workloads with RAS features like predictive failure analysis." },
{ brands::GCE, "Google Compute Engine (GCE) utilizes KVM-based virtualization with custom Titanium security chips for hardware root of trust. Features live migration during host maintenance and shielded VMs with UEFI secure boot. Underpins Google Cloud's Confidential Computing offering using AMD SEV-SNP memory encryption." },
Expand Down Expand Up @@ -676,7 +677,7 @@ std::string vm_description(const std::string& vm_brand) {
* @copyright MIT
*/
[[nodiscard]] static bool anyrun_driver() {
#if (!WINDOWS)
#if (!CLI_WINDOWS)
return false;
#else
HANDLE hFile;
Expand Down Expand Up @@ -710,7 +711,7 @@ std::string vm_description(const std::string& vm_brand) {
* @copyright MIT
*/
[[nodiscard]] static bool anyrun_directory() {
#if (!WINDOWS)
#if (!CLI_WINDOWS)
return false;
#else
NTSTATUS status;
Expand Down Expand Up @@ -771,7 +772,7 @@ void checker(const VM::enum_flags flag, const char* message) {
enum_name = grey + " [VM::" + VM::flag_to_string(flag) + "]" + ansi_exit;
}

#if (LINUX)
#if (CLI_LINUX)
if (are_perms_required(flag)) {
if (arg_bitset.test(COMPACT)) {
return;
Expand Down Expand Up @@ -810,7 +811,7 @@ void checker(const VM::enum_flags flag, const char* message) {
// that are embedded in the CLI because it was removed in the lib as of 2.0
void checker(const std::function<bool()>& func, const char* message) {
#if __cplusplus >= 201703L
if constexpr (!WINDOWS) {
if constexpr (!CLI_WINDOWS) {
if (arg_bitset.test(VERBOSE)) {
unsupported_count++;
}
Expand All @@ -822,7 +823,7 @@ void checker(const std::function<bool()>& func, const char* message) {
supported_count++;
}
#else
#if !WINDOWS
#if !CLI_WINDOWS
if (arg_bitset.test(VERBOSE)) {
unsupported_count++;
}
Expand Down Expand Up @@ -875,7 +876,7 @@ void general() {
notes_enabled = true;
}

#if (LINUX)
#if (CLI_LINUX)
if (notes_enabled && !is_admin()) {
std::cout << note << " Running under root might give better results\n";
}
Expand Down Expand Up @@ -1011,13 +1012,13 @@ void general() {
{
std::string brand = vm.brand;

if (is_anyrun && (brand == "Unknown")) {
if (is_anyrun && (brand == brands::NULL_BRAND)) {
brand = "ANY.RUN";
}

const bool is_red = (
(brand == "Unknown") ||
(brand == "Hyper-V artifact (not an actual VM)")
(brand == brands::NULL_BRAND) ||
(brand == brands::HYPERV_ARTIFACT)
);

std::cout << bold << "VM brand: " << ansi_exit << (is_red ? red : green) << brand << ansi_exit << "\n";
Expand All @@ -1030,11 +1031,11 @@ void general() {
std::string color = "";
std::string &type = vm.type;

if (is_anyrun && (type == "Unknown")) {
if (is_anyrun && (type == brands::NULL_BRAND)) {
type = "Sandbox";
}

if (type == "Unknown") {
if (type == brands::NULL_BRAND) {
color = red;
} else {
color = green;
Expand Down Expand Up @@ -1184,7 +1185,7 @@ void general() {


int main(int argc, char* argv[]) {
#if (WINDOWS)
#if (CLI_WINDOWS)
win_ansi_enabler_t ansi_enabler;
#endif

Expand Down Expand Up @@ -1311,7 +1312,7 @@ int main(int argc, char* argv[]) {
if (arg_bitset.test(BRAND)) {
std::string brand = VM::brand(VM::NO_MEMO, VM::MULTIPLE, settings());

if (is_anyrun && (brand == "Unknown")) {
if (is_anyrun && (brand == brands::NULL_BRAND)) {
brand = "ANY.RUN";
}

Expand All @@ -1323,7 +1324,7 @@ int main(int argc, char* argv[]) {
if (arg_bitset.test(TYPE)) {
std::string type = VM::type(VM::NO_MEMO, VM::MULTIPLE, settings());

if (is_anyrun && (type == "Unknown")) {
if (is_anyrun && (type == brands::NULL_BRAND)) {
type = "Sandbox";
}

Expand All @@ -1336,7 +1337,7 @@ int main(int argc, char* argv[]) {
std::string conclusion = VM::conclusion(VM::NO_MEMO, VM::MULTIPLE, settings());

if (is_anyrun) {
const std::string original = "Unknown";
const std::string original = brands::NULL_BRAND;
const std::string new_brand = "ANY.RUN";

replace(conclusion, original, new_brand);
Expand Down
39 changes: 33 additions & 6 deletions src/vmaware.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ MSVC_DISABLE_WARNING(ASSIGNMENT_OPERATOR NO_INLINE_FUNC SPECTRE)
* TL;DR I have wonky fingers :(
*/
namespace brands {
static constexpr const char* NULL_BRAND = "Unknown";
static constexpr const char* VBOX = "VirtualBox";
static constexpr const char* VMWARE = "VMware";
static constexpr const char* VMWARE_EXPRESS = "VMware Express";
Expand Down Expand Up @@ -534,7 +535,6 @@ namespace brands {
static constexpr const char* NOIRVISOR = "NoirVisor";
static constexpr const char* QIHOO = "Qihoo 360 Sandbox";
static constexpr const char* NSJAIL = "nsjail";
static constexpr const char* NULL_BRAND = "Unknown";
}


Expand Down Expand Up @@ -1200,12 +1200,11 @@ struct VM {
// memoization
struct memo {
private:
using result_t = bool;
using points_t = u8;

public:
struct data_t {
result_t result;
bool result;
points_t points;
};

Expand All @@ -1214,7 +1213,7 @@ struct VM {
static flagset cache_keys;

public:
static void cache_store(const u16 technique_macro, const result_t result, const points_t points) {
static void cache_store(const u16 technique_macro, const bool result, const points_t points) {
cache_table[technique_macro] = { result, points };
cache_keys.set(technique_macro);
}
Expand Down Expand Up @@ -10269,7 +10268,7 @@ struct VM {
return false;
}

[[nodiscard]] static bool is_setting_flag_set(const flagset& flags) {
[[nodiscard]] static bool is_setting_flag_set(const flagset& flags) {
for (std::size_t i = settings_begin; i < settings_end; i++) {
if (flags.test(i)) {
return true;
Expand Down Expand Up @@ -10963,10 +10962,13 @@ struct VM {
// brand strings will be outputted if there's a conflict)
const bool is_multiple = core::is_enabled(flags, MULTIPLE);

// used for later
u16 score = 0;

// are all the techiques already run? if not, run them
// to fetch the necessary info to determine the brand
if (!memo::all_present() || core::is_enabled(flags, NO_MEMO)) {
core::run_all(flags);
score = core::run_all(flags);
}

// check if the result is already cached and return that instead
Expand Down Expand Up @@ -11148,6 +11150,25 @@ struct VM {
merge(TMP_VMWARE_HARD, TMP_WORKSTATION, TMP_VMWARE_HARD);


// this is added in case the lib detects a non-Hyper-X technique.
// A Hyper-X affiliated technique should make the overall score
// as 0, but this isn't the case if non-Hyper-X techniques were
// found. There may be a conflict between an Unknown and Hyper-V
// brand, which is exactly what this section is meant to handle.
// It will remove the Hyper-V artifact brand string from the
// std::map to pave the way for other brands to take precendence.
// One of the main reasons to do this is because it would look
// incredibly awkward if the brand was "Hyper-V artifacts (not an
// actual VM)", clearly stating that it's NOT a VM while the VM
// confirmation is true and percentage is 100%, as if that makes
// any sense whatsoever. That's what this part fixes.
if (brands.count(TMP_HYPERV_ARTIFACT) > 0) {
if (score > 0) {
brands.erase(TMP_HYPERV_ARTIFACT);
}
}


// the brand element, which stores the NAME (const char*) and the SCORE (u8)
using brand_element_t = std::pair<const char*, brand_score_t>;

Expand All @@ -11165,6 +11186,9 @@ struct VM {

std::string ret_str = brands::NULL_BRAND;




// if the multiple setting flag is NOT set, return the
// brand with the highest score. Else, return a std::string
// of the brand message (i.e. "VirtualBox or VMware").
Expand All @@ -11183,6 +11207,8 @@ struct VM {
ret_str = ss.str();
}



// cache the result if memoization is enabled
if (core::is_disabled(flags, NO_MEMO)) {
if (is_multiple) {
Expand All @@ -11193,6 +11219,7 @@ struct VM {
memo::brand::store(ret_str);
}
}


// debug stuff to see the brand scoreboard, ignore this
#ifdef __VMAWARE_DEBUG__
Expand Down