# How to Implement Custom VM Detection Techniques in VMAware

> Easily implement custom VM detection techniques in VMAware with our straightforward guide. Define, weigh, and register your functions for enhanced virtual machine security.

- Repository: [Louis/vmaware](https://github.com/kernelwernel/vmaware)
- Tags: how-to-guide
- Published: 2026-03-05

---

**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](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp#L12185-L12221).

## 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/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)](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

```cpp
#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`](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp#L12185-L12221).*

### Example 2: Lambda for Sandbox File Detection

```cpp
#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`](https://github.com/kernelwernel/vmaware/blob/main/docs/documentation.md#L30-L38).*

### Example 3: `std::function` Wrapper for Hypervisor Bit

```cpp
#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`](https://github.com/kernelwernel/vmaware/blob/main/docs/documentation.md#L46-L54).*

### Example 4: Multiple Concurrent Custom Techniques

```cpp
#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`](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp#L12845-L12848).
- **Include Path**: Always include [`vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/vmaware.hpp) in your translation unit and place registration code in `main()` or your library initialization routine.

## Summary

- **Define** a detection routine as a `bool`-returning callable (function, lambda, or `std::function`).
- **Assign** a certainty weight between 0 and 100 to control scoring impact.
- **Register** via `VM::add_custom(percent, function)` before any detection queries.
- **Respect** the 256 technique limit and percentage validation rules enforced by the framework.
- **Reference** the implementation in [[`src/vmaware.hpp`](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp)](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp) and real-world usageexamples in [[`src/cli.cpp`](https://github.com/kernelwernel/vmaware/blob/main/src/cli.cpp)](https://github.com/kernelwernel/vmaware/blob/main/src/cli.cpp).

## 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`](https://github.com/kernelwernel/vmaware/blob/main/src/vmaware.hpp#L12845-L12848), aggregating all results into the final VM score and brand determination.