How to Implement Custom VM Detection Techniques in VMAware

To implement custom VM detection techniques in VMAware, define a callable that returns bool, assign a certainty weight from 0 to 100, and register it via VM::add_custom(percentage, function) before invoking any detection queries.

VMAware provides a modular VM detection framework that supports runtime extension through custom detection techniques. While the library ships with extensive built-in heuristics, security researchers often need to add proprietary checks for specific hypervisors or sandbox environments. The framework accommodates this through the VM::add_custom() API, which injects user-defined logic into the standard detection pipeline according to the source implementation.

Understanding the VM::add_custom() API Architecture

The VM::add_custom() function creates a core::custom_technique entry containing your detection function, a generated technique ID, and the specified percentage weight. This entry is appended to the internal core::custom_table defined at [lines 12845-12848 of vmaware.hpp](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp#L12845-L12848). During execution, the core detection loop iterates over this table after processing built-in techniques, incorporating your custom results into the global VM score and brand-scoring logic. The public documentation at [docs/documentation.md](https://github.com/kernelwernel/vmaware/blob/main/docs/documentation.md#L16-L38) provides the interface contract and usage constraints.

Step-by-Step Implementation Guide

Define the Detection Logic

Your detection routine must be a callable that accepts no arguments and returns a bool. Return true when your check positively identifies a virtual machine or sandbox; return false otherwise. This can be a regular function, a lambda expression, or a std::function<bool()> object.

Assign Certainty Weights

Specify an integer percentage between 0 and 100 that represents how strongly a positive result should contribute to the overall VM detection score. Higher values increase the likelihood that VM::detect() returns true when your check succeeds.

Register with add_custom Before Detection

You must call VM::add_custom(percentage, detection_func) before any other VMAware call that triggers detection, such as VM::detect(), VM::brand(), or VM::conclusion(). Registration after these calls will be ignored by the detection engine.

Respect the 256 Technique Limit

VMAware reserves space for a maximum of 256 custom techniques (MAX_CUSTOM_TECHNIQUES). Attempting to register beyond this limit will throw an exception. The function also validates that your percentage argument falls within the 0-100 range, throwing std::invalid_argument if the value is out of bounds.

Practical Code Examples for Custom Detection

Example 1: Function Pointer for QEMU CPU Detection

#include "vmaware.hpp"
#include <string>

bool detects_qemu_cpu() {
    // Check CPU brand string for "QEMU"
    return std::string(VM::cpu::get_brand()).find("QEMU") != std::string::npos;
}

int main() {
    // Register with a 60% certainty weight
    VM::add_custom(60, detects_qemu_cpu);
    
    if (VM::detect()) {
        std::cout << "VM detected (including custom checks)\n";
    }
}

Source reference: Implementation details at vmaware.hpp:12185-12221.

Example 2: Lambda for Sandbox File Detection

#include "vmaware.hpp"
#include <fstream>

int main() {
    // 40% weight, detects a sandbox file on disk
    VM::add_custom(40, []() -> bool {
        std::ifstream f("/tmp/sandbox_marker");
        return f.good();  // true indicates likely VM/sandbox
    });

    std::cout << "Result: " << VM::conclusion() << '\n';
}

Source reference: Lambda usage pattern at documentation.md:30-38.

Example 3: std::function Wrapper for Hypervisor Bit

#include "vmaware.hpp"
#include <functional>
#include <iostream>

int main() {
    std::function<bool()> has_hypervisor_bit = [] {
        // Reuse VMAware's built-in check as a custom rule
        return VM::check(VM::HYPERVISOR_BIT);
    };

    // 30% weight; treat built-in check as custom logic
    VM::add_custom(30, has_hypervisor_bit);

    std::cout << "Detected? " << std::boolalpha << VM::detect() << '\n';
}

Source reference: std::function usage at documentation.md:46-54.

Example 4: Multiple Concurrent Custom Techniques

#include "vmaware.hpp"
#include <filesystem>
#include <cstdlib>

int main() {
    // Technique 1: Check for OpenVZ proc entry (25% weight)
    VM::add_custom(25, [] { 
        return std::filesystem::exists("/proc/vz"); 
    });
    
    // Technique 2: Check for container via systemd (35% weight)
    VM::add_custom(35, [] { 
        return std::system("systemd-detect-virt --container") == 0; 
    });

    std::cout << VM::brand() << " → " << VM::type() << '\n';
}

Note: All add_custom calls must precede detection queries; otherwise, they are excluded from the evaluation.

Critical Constraints and Validation Rules

  • Percentage Validation: The framework throws std::invalid_argument if you provide a percentage outside the 0-100 range.
  • Registration Deadline: Custom techniques must be added before the first call to VM::detect(), VM::brand(), or VM::conclusion().
  • Maximum Capacity: The hard limit of 256 custom techniques (MAX_CUSTOM_TECHNIQUES) prevents unbounded memory growth in the internal core::custom_table.
  • Include Path: Always include vmaware.hpp in your translation unit and place registration code in main() or your library initialization routine.

Summary

Frequently Asked Questions

What is the maximum number of custom techniques I can add to VMAware?

You can register up to 256 custom techniques per application instance. This limit is defined by the MAX_CUSTOM_TECHNIQUES constant in the VMAware core. Attempting to exceed this threshold results in an exception.

When should I call VM::add_custom() in my application lifecycle?

You must call VM::add_custom() before invoking any function that triggers the detection engine, such as VM::detect(), VM::brand(), or VM::conclusion(). Registration calls made after these functions execute will not be included in the detection results.

What happens if I provide an invalid percentage value to add_custom?

The function validates that your percentage argument falls within the inclusive range of 0 to 100. If you provide a value outside this range, VM::add_custom() throws a std::invalid_argument exception immediately.

Can I use custom techniques alongside VMAware's built-in detection methods?

Yes. Custom techniques operate transparently alongside the library's built-in heuristics. During a detection run, VMAware evaluates its internal technique table first, then processes your custom entries from the core::custom_table, aggregating all results into the final VM score and brand determination.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →