Skip to content

Dev #244

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 22 commits into from
Feb 5, 2025
Merged

Dev #244

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The library is:
- Cross-platform (Windows + MacOS + Linux)
- Features up to 120+ unique VM detection techniques [[list](https://github.com/kernelwernel/VMAware/blob/main/docs/documentation.md#flag-table)]
- Features the most cutting-edge techniques
- Able to detect 50+ VM brands including VMware, VirtualBox, QEMU, Hyper-V, and much more [[list](https://github.com/kernelwernel/VMAware/blob/main/docs/documentation.md#brand-table)]
- Able to detect 60+ VM brands including VMware, VirtualBox, QEMU, Hyper-V, and much more [[list](https://github.com/kernelwernel/VMAware/blob/main/docs/documentation.md#brand-table)]
- Able to beat VM hardeners
- Compatible with x86 and ARM, with backwards compatibility for 32-bit systems
- Very flexible, with total fine-grained control over which techniques get executed
Expand Down Expand Up @@ -136,10 +136,16 @@ endif()
The module file and function version is located [here](auxiliary/vmaware_download.cmake)


### Vcpkg installation
```
vcpkg install vmaware-vm-detection
```


<br>

## Documentation 📒
You can view the full docs [here](docs/documentation.md). All the details such as functions, techniques, settings and examples are provided. Trust me, it's not too intimidating ;)
You can view the full docs [here](docs/documentation.md). All the details such as functions, techniques, settings, and examples are provided. Trust me, it's not too intimidating ;)

<br>

Expand Down Expand Up @@ -218,7 +224,7 @@ You can view the full docs [here](docs/documentation.md). All the details such a

> I would've made it strictly MIT so proprietary software can make use of the library, but some of the techniques employed are from GPL 3.0 projects, and I have no choice but to use the same license for legal reasons.
>
> This gave me an idea to make an MIT version without all of the GPL code so it can also be used without forcing your code to be open-source. It should be noted that the MIT version removes <b>9</b> techniques out of 128 (as of 2.0 version), and the lesser the number of techniques, the less accurate the overall result might be.
> This gave me an idea to make an MIT version without all of the GPL code so it can also be used without forcing your code to be open-source. It should be noted that the MIT version removes <b>9</b> techniques out of 126 (as of 2.0 version), and the lesser the number of techniques, the less accurate the overall result might be.

</details>

Expand All @@ -239,7 +245,7 @@ And if you found this project useful, a star would be appreciated :)

<br>

## Credits and contributors ✒️
## Credits, contributors, and acknowledgements ✒️
- [Requiem](https://github.com/NotRequiem) (Co-maintainer)
- [Check Point Research](https://research.checkpoint.com/)
- [Unprotect Project](https://unprotect.it/)
Expand Down
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- [ ] implement techniques from virt-what
- [ ] https://cloud.google.com/compute/docs/instances/detect-compute-engine
- [ ] support the odd_thread_count technique for AMD
- [ ] add WMI memo line details in sections category of the banner

# Distant plans
- add the library to conan.io when released
Expand Down
2 changes: 1 addition & 1 deletion auxiliary/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ def update_sections(filename):

# get the index file line of the section string
section_line = 0
section_str = " * ================================ SECTIONS =================================="
section_str = " * ============================== SECTIONS =================================="
for line in header_content:
if section_str in line:
break
Expand Down
23 changes: 14 additions & 9 deletions docs/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ VMAware provides a convenient way to not only check for VMs, but also have the f
| `VM::MUTEX` | Check for mutex strings of VM brands | Windows | 85% | | | | |
| `VM::ODD_CPU_THREADS` | Check for odd CPU threads, usually a sign of modification through VM setting because 99% of CPUs have even numbers of threads | | 80% | | | | |
| `VM::INTEL_THREAD_MISMATCH` | Check for Intel CPU thread count database if it matches the system's thread count | | 100% | | | | |
| `VM::XEON_THREAD_MISMATCH` | Same as above, but for Xeon Intel CPUs | | 85% | | | | |
| `VM::XEON_THREAD_MISMATCH` | Same as above, but for Xeon Intel CPUs | | 100% | | | | |
| `VM::NETTITUDE_VM_MEMORY` | Check for memory regions to detect VM-specific brands | Windows | 100% | | | | |
| `VM::CPUID_BITSET` | Check for CPUID technique by checking whether all the bits equate to more than 4000 | | 25% | | | | |
| `VM::CUCKOO_DIR` | Check for cuckoo directory using crt and WIN API directory functions | Windows | 30% | | | | |
Expand Down Expand Up @@ -432,7 +432,7 @@ VMAware provides a convenient way to not only check for VMs, but also have the f
| `VM::DRIVER_NAMES` | Check for VM-specific names for drivers | Windows | 100% | | | | |
| `VM::VM_SIDT` | Check for unknown IDT base address | Windows | 100% | | | | |
| `VM::HDD_SERIAL` | Check for HDD serial number | Windows | 100% | | | | |
| `VM::PORT_CONNECTORS` | Check for physical connection ports | Windows | 10% | | | | |
| `VM::PORT_CONNECTORS` | Check for physical connection ports | Windows | 25% | | | | |
| `VM::VM_HDD` | Check for VM related keywords in HDD models | Windows | 100% | | | | |
| `VM::ACPI_REGISTRY` | Check for VM related strings in ACPI data | Windows | 100% | | | | |
| `VM::GPU_NAME` | Check for VM specific device names in GPUs | Windows | 100% | | | | |
Expand All @@ -449,16 +449,19 @@ VMAware provides a convenient way to not only check for VMs, but also have the f
| `VM::VMWARE_HARDENER` | Checks for VMwareHardenerLoader's method of patching firmware detection by setting its signatures with "7" | Windows | 60% | | | | |
| `VM::SYS_QEMU` | Check for existence of "qemu_fw_cfg" directories within /sys/module and /sys/firmware | Linux | 70% | | | | |
| `VM::LSHW_QEMU` | Check for QEMU string instances with lshw command | Linux | 80% | | | | |
| `VM::VIRTUAL_PROCESSORS` | Checks if the number of maximum virtual processors matches the maximum number of logical processors | Windows | 50% | | | | |
| `VM::VIRTUAL_PROCESSORS` | Check if the number of maximum virtual processors matches the maximum number of logical processors | Windows | 50% | | | | |
| `VM::MOTHERBOARD_PRODUCT` | Check if the motherboard product string matches "Virtual Machine" | Windows | 50% | | | | |
| `VM::HYPERV_QUERY` | Checks if a call to NtQuerySystemInformation with the 0x9f leaf fills a _SYSTEM_HYPERVISOR_DETAIL_INFORMATION structure | Windows | 100% | | | | |
| `VM::BAD_POOLS` | Checks for system pools allocated by hypervisors | Windows | 80% | | | | |
| `VM::HYPERV_QUERY` | Check if a call to NtQuerySystemInformation with the 0x9f leaf fills a _SYSTEM_HYPERVISOR_DETAIL_INFORMATION structure | Windows | 100% | | | | |
| `VM::BAD_POOLS` | Check for system pools allocated by hypervisors | Windows | 80% | | | | |
| `VM::AMD_SEV` | Check for AMD-SEV MSR running on the system | Linux and MacOS | 50% | Admin | | | |
| `VM::AMD_THREAD_MISMATCH` | Check for AMD CPU thread count database if it matches the system's thread count | | 100% | | | | |
| `VM::NATIVE_VHD` | Checks if the OS was booted from a VHD container | | 100% | | | | |
| `VM::VIRTUAL_REGISTRY` | Checks for particular object directory which is present in Sandboxie virtual environment but not in usual host systems | | 65% | | | | |
| `VM::FIRMWARE_SCAN` | Checks for VM signatures in firmware | | 90% | | | | |
<!-- ADD DETAILS HERE -->
| `VM::NATIVE_VHD` | Check for OS being booted from a VHD container | Windows | 100% | | | | |
| `VM::VIRTUAL_REGISTRY` | Check for particular object directory which is present in Sandboxie virtual environment but not in usual host systems | Windows | 65% | | | | |
| `VM::FIRMWARE_SCAN` | Check for VM signatures in firmware | Windows | 90% | | | | |
| `VM::NX_BIT` | Check for AMD64/Intel64 architecture without NX support | Windows | 50% | | | | |
| `VM::FILE_ACCESS_HISTORY` | Check if the number of accessed files are too low for a human-managed environment | Linux | 15% | | | | |


<br>

Expand Down Expand Up @@ -533,6 +536,8 @@ This is the table of all the brands the lib supports.
| AMD SEV-SNP | `VM::brands::AMD_SEV_SNP` | VM encryptor | |
| Neko Project II | `VM::brands::NEKO_PROJECT` | Emulator | |
| Google Compute Engine (KVM) | `VM::brands::GCE` | Cloud VM service | |
| NoirVisor | `VM::brands::NOIRVISOR` | Hypervisor (type 1) | |
| Qihoo 360 Sandbox | `VM::brands::QIHOO` | Sandbox | |

<br>

Expand Down Expand Up @@ -572,7 +577,7 @@ This is the table of all the brands the lib supports.
| -t | --type | Returns the VM type (if a VM was found) |
| | --disable-notes | No notes will be provided |
| | --high-threshold | A higher theshold bar for a VM detection will be applied |
| | --no-color | Removes all the color, this is added due to some terminals not supporting ANSI escape codes while cluttering the output |
| | --no-ansi | Removes all the ANSI encodings (color and text style). This is added due to some terminals not supporting ANSI escape codes while cluttering the output |
| | --dynamic | allow the conclusion message to be dynamic (8 possibilities instead of only 2) |
| | --verbose | add more information to the output |
| | --compact | ignore the unsupported techniques from the CLI output and thus make it more compact |
Expand Down
9 changes: 7 additions & 2 deletions src/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
| file | purpose |
| File | Purpose |
|------|---------|
| `cli.cpp` | Entire CLI tool code |
| `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. This removes 9 techniques out of ~120, however. |
| `vmaware_MIT.hpp` | Same as above but in MIT. But this removes 9 techniques out of 126 |


> [!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.
66 changes: 56 additions & 10 deletions src/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ constexpr const char* ver = "2.0";
constexpr const char* date = "January 2025";

std::string bold = "\033[1m";
std::string underline = "\033[4m";
std::string ansi_exit = "\x1B[0m";
std::string red = "\x1B[38;2;239;75;75m";
std::string orange = "\x1B[38;2;255;180;5m";
Expand All @@ -60,6 +61,7 @@ std::string green_orange = "\x1B[38;2;174;197;59m";
std::string grey = "\x1B[38;2;108;108;108m";

using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;

enum arg_enum : u8 {
Expand All @@ -76,7 +78,7 @@ enum arg_enum : u8 {
TYPE,
NOTES,
HIGH_THRESHOLD,
NO_COLOR,
NO_ANSI,
DYNAMIC,
VERBOSE,
COMPACT,
Expand Down Expand Up @@ -156,7 +158,7 @@ R"(Usage:
Extra:
--disable-notes no notes will be provided
--high-threshold a higher theshold bar for a VM detection will be applied
--no-color self explanatory
--no-ansi removes color and ansi escape codes from the output
--dynamic allow the conclusion message to be dynamic (8 possibilities instead of only 2)
--verbose add more information to the output
--compact ignore the unsupported techniques from the CLI output
Expand All @@ -178,7 +180,7 @@ R"(Usage:
}

const char* color(const u8 score) {
if (arg_bitset.test(NO_COLOR)) {
if (arg_bitset.test(NO_ANSI)) {
return "";
}

Expand Down Expand Up @@ -268,6 +270,7 @@ AMD SEV
AMD SEV-ES
AMD SEV-SNP
Neko Project II
Qihoo 360 Sandbox
NoirVisor
)";

Expand Down Expand Up @@ -384,6 +387,7 @@ bool is_unsupported(VM::enum_flags flag) {
case VM::LSHW_QEMU:
case VM::AMD_SEV:
case VM::AMD_THREAD_MISMATCH:
case VM::FILE_ACCESS_HISTORY:
// ADD LINUX FLAG
return false;
default: return true;
Expand Down Expand Up @@ -478,6 +482,7 @@ bool is_unsupported(VM::enum_flags flag) {
case VM::NATIVE_VHD:
case VM::VIRTUAL_REGISTRY:
case VM::FIRMWARE_SCAN:
case VM::NX_BIT:
// ADD WINDOWS FLAG
return false;
default: return true;
Expand Down Expand Up @@ -665,6 +670,7 @@ std::string vm_description(const std::string& vm_brand) {
{ VM::brands::AMD_SEV_SNP, "AMD SEV-Secure Nested Paging (SEV-SNP) adds memory integrity protection to SEV-ES. Uses reverse map tables (RMP) to prevent hypervisor-mediated replay/spoofing attacks. Enables attested launch for cloud workloads via guest policy certificates and AMD's Key Distribution Service (KDS)." },
{ VM::brands::NEKO_PROJECT, "Neko Project II is an emulator designed for emulating PC-98 computers. They are a lineup of Japanese 16-bit and 32-bit personal computers manufactured by NEC from 1982 to 2003. While based on Intel processors, it uses an in-house architecture making it incompatible with IBM clones." },
{ VM::brands::NOIRVISOR, "NoirVisor is a hardware-accelerated hypervisor with support to complex functions and purposes. It is designed to support processors based on x86 architecture with hardware-accelerated virtualization feature. For example, Intel processors supporting Intel VT-x or AMD processors supporting AMD-V meet the requirement. It was made by Zero-Tang." },
{ VM::brands::QIHOO, "360 sandbox is a part of 360 Total Security. Similar to other sandbox software, it provides a virtualized environment where potentially malicious or untrusted programs can run without affecting the actual system. Qihoo 360 Sandbox is commonly used for testing unknown applications, analyzing malware behavior, and protecting users from zero-day threats." },
{ VM::brands::NULL_BRAND, "Indicates no detectable virtualization brand. This result may occur on bare-metal systems, unsupported/obscure hypervisors, or when anti-detection techniques (e.g., VM escaping) are employed by the guest environment." }
};

Expand Down Expand Up @@ -852,7 +858,7 @@ const bool is_anyrun = (is_anyrun_directory || is_anyrun_driver);
void general() {
bool notes_enabled = false;

if (arg_bitset.test(NO_COLOR)) {
if (arg_bitset.test(NO_ANSI)) {
detected = ("[ DETECTED ]");
not_detected = ("[NOT DETECTED]");
no_support = ("[ NO SUPPORT ]");
Expand All @@ -861,6 +867,7 @@ void general() {
disabled = ("[ DISABLED ]");

bold = "";
underline = "";
ansi_exit = "";
red = "";
orange = "";
Expand Down Expand Up @@ -1007,7 +1014,8 @@ void general() {
checker(VM::NATIVE_VHD, "VHD containers");
checker(VM::VIRTUAL_REGISTRY, "registry emulation");
checker(VM::FIRMWARE_SCAN, "firmware signatures");

checker(VM::NX_BIT, "NX/XD anomalies");
checker(VM::FILE_ACCESS_HISTORY, "low file access count");
// ADD NEW TECHNIQUE CHECKER HERE

std::printf("\n");
Expand Down Expand Up @@ -1123,11 +1131,49 @@ void general() {
{
if (vm.brand != VM::brands::NULL_BRAND) {

std::string description = vm_description(vm.brand);
const std::string description = vm_description(vm.brand);

if (!description.empty()) {
std::cout << bold << "VM description: " << ansi_exit << "\n" << description << "\n\n";
//std::cout << note << " The result means that the CLI has found Hyper-V, but as an artifact instead of an actual VM. This means that although the hardware values in fact match with Hyper-V due to how it's designed by Microsoft, the CLI has determined you are NOT in a Hyper-V VM.\n\n";
std::cout << bold << underline << "VM description:" << ansi_exit << "\n";

// this basically adds a \n for every 50 characters after a space
// so that the output doesn't wrap around the console while making
// it harder to read. Kinda like how this comment you're reading is
// structured by breaking the lines in a clean and organised way.
const u8 max_line_length = 60;

std::vector<std::string> divided_description;

std::istringstream stream(description);
std::string word_snippet;

// extract words separated by spaces
while (stream >> word_snippet) {
divided_description.push_back(word_snippet);
}

std::size_t char_count = 0;

for (auto it = divided_description.begin(); it != divided_description.end(); ++it) {
char_count += it->length() + 1; // +1 because of the space

if (char_count <= 60) {
continue;
} else {
if ((char_count - 1) >= (max_line_length + 3)) {
it = divided_description.insert(it + 1, "\n");
char_count = it->length() + 1;
} else {
continue;
}
}
}

for (const auto& str : divided_description) {
std::cout << str << ((str != "\n") ? " " : "");
}

std::printf("\n\n");
}
}
}
Expand Down Expand Up @@ -1206,7 +1252,7 @@ int main(int argc, char* argv[]) {
{ "--verbose", VERBOSE },
{ "--compact", COMPACT },
{ "--mit", MIT },
{ "--no-color", NO_COLOR }
{ "--no-color", NO_ANSI }
}};

std::string potential_null_arg = "";
Expand Down Expand Up @@ -1256,7 +1302,7 @@ int main(int argc, char* argv[]) {
static_cast<u32>(arg_bitset.test(BRAND)) +
static_cast<u32>(arg_bitset.test(TYPE)) +
static_cast<u32>(arg_bitset.test(CONCLUSION))
);
);

if (returners > 0) { // at least one of the options are set
if (returners > 1) { // more than 2 options are set
Expand Down
Loading