CybersecurityDev

Malware Dev – Chapter 06 – Anti-VM Strategies

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, &registryKey);
  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, &registryKey);
  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.