Continued series from the Malware Development for Ethical Hackers Book.
GitHub repo: EricTurner3 – Malware_Development.
Filesystem Detection Techniques
VirtualBox Machine Detection
The book showcases 8 different files to test for a VirtualBox, however, the sample code only checks for 2/8 files. I created a modified source code that uses an array to check for all of these and print out if one is detected.
/*
Anti-VM - VirtualBox File Detect
15 Feb 2025
Eric
To build: x86_64-w64-mingw32-g++ -O2 06_vbox_file_detect.c -o VBoxFile.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
*/
#include <windows.h>
#include <stdio.h>
BOOL checkVM() {
// Paths to check
const char* paths[] = {
"c:\\windows\\system32\\drivers\\VBoxMouse.sys",
"c:\\windows\\system32\\drivers\\VBoxGuest.sys",
"c:\\windows\\system32\\drivers\\VBoxSF.sys",
"c:\\windows\\system32\\drivers\\VBoxVideo.sys",
"c:\\windows\\system32\\vboxdisp.dll",
"c:\\windows\\system32\\vboxhook.dll",
"c:\\windows\\system32\\vboxservice.exe",
"c:\\windows\\system32\\vboxtray.exe"
};
// placeholder, default to FALSE
BOOL vm_detected = FALSE;
// loop through the filepaths to see if any exist
for (size_t i = 0; i < (sizeof(paths) / sizeof(paths[0])); ++i){
DWORD attributes = GetFileAttributes(paths[i]);
if (attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY)){
printf("VirtualBox File Found: %s \n", paths[i]);
vm_detected = TRUE;
break;
}
}
return vm_detected;
}
int main() {
if (checkVM()) {
printf("The system appears to be a virtual machine.\n");
} else {
printf("The system does not appear to be a virtual machine.\n");
}
return 0;
}
Hardware Detection
The book uses some sample code to check the HDD Vendor ID to detect for Virtual Machine. I think this approach is not useful, as my VM did not have a \\PhysicalDrive0, it has a HarddiskVolume1 similar to my non-VM Windows machine. The sample code ended up failing on my VM and stated it was not a virtual machine.
Time Detection
The book uses NTDelayExecution and capturing the before / after time to determine if it slept the appropriate amount of milliseconds. The example uses 800ms > time < 1000ms to detect. On my actual machine, it nailed 1000ms on the dot, but was still marked as a virtual machine. Setting it to 1000 ms > time < 1000ms tightens the execution to perfect. The VM runs at 1031ms. I’m curious if a slower or much older computer would end up triggering as a VM as well.
Registry Detection
This example checks for the existence of registry keys and checks if the value equals something in particular. This is what I was referring to earlier in Hardware Detection, we are able to check for System Product Name or BiosVersion to detect VirtualBox. I removed the payload from my example and defaulted back to simple message boxes again.
/*
Anti-VM - Registry Detect
15 Feb 2025
Eric
x86_64-w64-mingw32-g++ -O2 06_registry.c -o VMRegistry.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
int checkRegistryKey(HKEY rootKey, char* subKeyName) {
HKEY registryKey = NULL;
LONG result = RegOpenKeyExA(rootKey, subKeyName, 0, KEY_READ, ®istryKey);
if (result == ERROR_SUCCESS) {
RegCloseKey(registryKey);
return TRUE;
}
return FALSE;
}
int compareRegistryKeyValue(HKEY rootKey, char* subKeyName, char* registryValue, char* comparisonValue) {
HKEY registryKey = NULL;
LONG result;
char value[1024];
DWORD size = sizeof(value);
result = RegOpenKeyExA(rootKey, subKeyName, 0, KEY_READ, ®istryKey);
if (result == ERROR_SUCCESS) {
RegQueryValueExA(registryKey, registryValue, NULL, NULL, (LPBYTE)value, &size);
if (result == ERROR_SUCCESS) {
if (strcmp(value, comparisonValue) == 0) {
return TRUE;
}
}
}
return FALSE;
}
int main(int argc, char* argv[]) {
HANDLE processHandle; // Process handle
HANDLE remoteThread; // Remote thread
PVOID remoteBuffer; // Remote buffer
if (checkRegistryKey(HKEY_LOCAL_MACHINE, "HARDWARE\\ACPI\\FADT\\VBOX__")) {
printf("VirtualBox VM registry path value detected\n");
MessageBox(NULL, "Virtual Machine Detected", "Program", MB_OK);
return -2;
}
if (compareRegistryKeyValue(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\SystemInformation",
"SystemProductName", "VirtualBox")) {
printf("VirtualBox VM registry key value detected\n");
MessageBox(NULL, "Virtual Machine Detected", "Program", MB_OK);
return -2;
}
if (compareRegistryKeyValue(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\SystemInformation",
"BiosVersion", "VirtualBox")) {
printf("VirtualBox VM BIOS version detected\n");
MessageBox(NULL, "Virtual Machine Detected", "Program", MB_OK);
return -2;
}
MessageBox(NULL, "Running Hack", "Program", MB_OK);
return 0;
}
Conclusion
There were some interesting techniques for virtual machine detection. Most of these seemed very rudimentary to be able to evade. I am curious what detections could be used that aren’t as easy to defeat but still promote high accuracy.