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_argumentif 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(), orVM::conclusion(). - Maximum Capacity: The hard limit of 256 custom techniques (
MAX_CUSTOM_TECHNIQUES) prevents unbounded memory growth in the internalcore::custom_table. - Include Path: Always include
vmaware.hppin your translation unit and place registration code inmain()or your library initialization routine.
Summary
- Define a detection routine as a
bool-returning callable (function, lambda, orstd::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) and real-world usageexamples in [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, 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →