What are the different ways for a program to detect that it executes inside a virtualized environment ? And, would it be possible to detect what kind of virtualization is used ?
the list could be endless, so I'll keep it short:
- virtualized environment artifacts: registry keys, hard disk name, network card address, specific drivers,...
- environment differences: no mouse, internet connection, sound card,...
- execution difference: detection of block translation (create another thread and apply statistics on IP), different system registers values, ...
- lack of user interaction (specific for automated environment): no mouse movement, no file operations,...
- specific environment differences: VmWare backdoor, VirtualPC exception bug, ...
(check the anti-debug tag wiki for more)
There are a multitude of ways to detect virtual machines/emulators, mostly following the pattern of identifying an imperfection in the simulation and then testing for it.
At the simplest end, common virtualization toolkits plaster their name over all kinds of system drivers and devices. Simply looking at the name of network connections or their MAC address might be sufficient to identify VMware if not specifically configured to mask that. Likewise, the VM's memory may have plenty of strings that make the virtualization software's presence obvious.
Some other VM artifacts come from the necessity for both host and guest to have a data structure accessible to the processor that can't overlap, such as the SIDT assembly instruction to return the interrupt descriptor table register. (IDT) Virtual machines typically store the IDT at a higher register than a physical host.
Measuring the time of certain functions or instructions that would normally require interaction with the virtualization system is a way to indirectly infer you're executing in a VM.
Two approaches come to mind as anti-anti-VM methods: First, one can modify the virtual environment to remove all traces possible of virtualization, which can work well against simple checks for 'vmware' or similar strings, causing an arms race of sorts between known techniques and crafty vm configuration.
The second approach is to rely heavily on static analysis to identify VM detection techniques and patch them to neutralize their effect after doing so to yield a non-VM-aware executable that can then be dynamically analyzed.
A couple sources with good information, if a couple years old:
- http://www.symantec.com/avcenter/reference/Virtual_Machine_Threats.pdf - Peter Ferrie's Attacks on Virtual Machine emulators
- http://handlers.sans.org/tliston/ThwartingVMDetection_Liston_Skoudis.pdf - A 2006 presentation on different anti-Vm and anti-anti-VM techniques.
Here are some tricks for detecting VM's:
http://pastebin.com/RU6A2UuB (9 different methods, registry, dropped VBOX dlls, pipe names etc)
http://pastebin.com/xhFABpPL (Machine provider name)
http://pastebin.com/v8LnMiZs (Innotek trick)
http://pastebin.com/fPY4MiYq (Bios Brand and Bios Version)
http://pastebin.com/Geggzp4G (Bios Brand and Bios Version)
http://pastebin.com/T0s5gVGW (Parsing SMBiosData searching for newly-introduced or bizarre type)
http://pastebin.com/AjHWApes (Cadmus Mac Address Trick)
http://pastebin.com/wh4NAP26 (VBoxSharedFolderFS Trick)
http://pastebin.com/Nsv5B1yk (Resume Flag Trick)
http://pastebin.com/exAK5XQx (Reset Trick)
http://pastebin.com/HVActZMC (CPUID Trick)
Even though, I tried to make the code self explanatory, you can also refer to the corresponding blog posts for more detailed info.
I wrote a test program a while go (in Delphi).
The following two functions detect VMware and HyperV
// VMware detection as described by Elias Bachaalany function IsInsideVMware: Boolean; begin Result := True; try asm push edx; push ecx; push ebx; mov eax, 'VMXh'; mov ebx, 0; mov ecx, 10; mov edx, 'VX'; in eax, dx; cmp ebx, 'VMXh'; setz [Result]; pop ebx; pop ecx; pop edx; end; except Result := False; end; end; function IsHyperV: Boolean; asm cpuid; test ecx, ecx; sets [Result]; end;
The following function checks for Hyper-V via the Vendor Branding string (on VMware this returns "VMwareVMware":
function IsRunningUnderHyperV: BOOL; stdcall; var VMBranding: array[0..12] of AnsiChar; begin asm mov eax, $40000000; cpuid; mov dword ptr [VMBranding+0], ebx; // Get the VM branding string mov dword ptr [VMBranding+4], ecx; mov dword ptr [VMBranding+8], edx; end; VMBranding := #0; Result := CompareText(String(VMBranding), 'Microsoft Hv') = 0; end;
In addons on the answers post before, cuckoosandbox implements few yara rules for vm detection:
You can find common tricks in cuckoo sandbox repository.
Just as a kind of related note, but side-stepping the actual question a bit. There was a presentation at the VB conference last year (2013) in Berlin, about a KVM-based modified hypervisor. It is called CXPInspector and the presentation they gave (the first one in the tech stream) can be found here.
The method makes use of newer processor features. The presentation gives a nice overview. Basically the only conceivable attack - aside from those based on flaws in the CPU and the hypervisor implementation - would be a timing attack. And even though many machines these days are fast, that's not exactly a very reliable method. It used to be, but these days it's gambling, at best.
Here is a collection of anti-sandbox/vm/debugger techniques implemented in a open source program which will give you a clear idea how to detect virtualization: https://github.com/LordNoteworthy/al-khaser.
Here are the list of supported techniques:
- Process Environement Block (BeingDebugged)
- Process Environement Block (NtGlobalFlag)
- ProcessHeap (Flags)
- ProcessHeap (ForceFlags)
- NtQueryInformationProcess (ProcessDebugPort)
- NtQueryInformationProcess (ProcessDebugFlags)
- NtQueryInformationProcess (ProcessDebugObject)
- NtSetInformationThread (HideThreadFromDebugger)
- NtQueryObject (ObjectTypeInformation)
- NtQueryObject (ObjectAllTypesInformation)
- CloseHanlde (NtClose) Invalide Handle
- SetHandleInformation (Protected Handle)
- OutputDebugString (GetLastError())
- Hardware Breakpoints (SEH / GetThreadContext)
- Software Breakpoints (INT3 / 0xCC)
- Memory Breakpoints (PAGE_GUARD)
- Interrupt 0x2d
- Interrupt 1
- Parent Process (Explorer.exe)
- SeDebugPrivilege (Csrss.exe)
- NtYieldExecution / SwitchToThread
- TLS callbacks
- Erase PE header from memory
Timing Attacks [Anti-Sandbox]
- RDTSC (with CPUID to force a VM Exit)
- RDTSC (Locky version with GetProcessHeap & CloseHandle)
- Sleep -> SleepEx -> NtDelayExecution
- Sleep (in a loop a small delay)
- Sleep and check if time was accelerated (GetTickCount)
- SetTimer (Standard Windows Timers)
- timeSetEvent (Multimedia Timers)
- WaitForSingleObject -> WaitForSingleObjectEx -> NtWaitForSingleObject
- WaitForMultipleObjects -> WaitForMultipleObjectsEx ->
Human Interaction / Generic [Anti-Sandbox]
- Mouse movement
- Total Physical memory (GlobalMemoryStatusEx)
- Disk size using DeviceIoControl (IOCTL_DISK_GET_LENGTH_INFO)
- Disk size using GetDiskFreeSpaceEx (TotalNumberOfBytes)
- Count of processors (Win32/Tinba - Win32/Dyre)
Anti-Virtualization / Full-System Emulation
Registry key value artifacts
- HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0 (Identifier) (VBOX)
- HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0 (Identifier) (QEMU)
- HARDWARE\Description\System (SystemBiosVersion) (VBOX)
- HARDWARE\Description\System (SystemBiosVersion) (QEMU)
- HARDWARE\Description\System (VideoBiosVersion) (VIRTUALBOX)
- HARDWARE\Description\System (SystemBiosDate) (06/23/99)
- HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0 (Identifier) (VMWARE)
- HARDWARE\DEVICEMAP\Scsi\Scsi Port 1\Scsi Bus 0\Target Id 0\Logical Unit Id 0 (Identifier) (VMWARE)
- HARDWARE\DEVICEMAP\Scsi\Scsi Port 2\Scsi Bus 0\Target Id 0\Logical Unit Id 0 (Identifier) (VMWARE)
Registry Keys artifacts
- "SOFTWARE\Oracle\VirtualBox Guest Additions"
- SOFTWARE\VMware, Inc.\VMware Tools
File system artifacts
- "%PROGRAMFILES%\oracle\virtualbox guest additions\"
- Interupt Descriptor Table (IDT) location
- Local Descriptor Table (LDT) location
- Global Descriptor Table (GDT) location
- Task state segment trick with STR
- "\x08\x00\x27" (VBOX)
- "\x00\x05\x69" (VMWARE)
- "\x00\x0C\x29" (VMWARE)
- "\x00\x1C\x14" (VMWARE)
- "\x00\x50\x56" (VMWARE)
Hardware Device information
- SetupAPI SetupDiEnumDeviceInfo (GUID_DEVCLASS_DISKDRIVE)
- VIRTUAL HD
- SetupAPI SetupDiEnumDeviceInfo (GUID_DEVCLASS_DISKDRIVE)
- VirtualBox Shared Folders
- vboxservice.exe (VBOX)
- vboxtray.exe (VBOX)
- vmtoolsd.exe (VMWARE)
- vmwaretray.exe (VMWARE)
- vmwareuser (VMWARE)
- vmsrvc.exe (VirtualPC)
- vmusrvc.exe (VirtualPC)
- prl_cc.exe (Parallels)
- prl_tools.exe (Parallels)
- xenservice.exe (Citrix Xen)
- SELECT * FROM Win32_Bios (SerialNumber) (VMWARE)
- SELECT * FROM Win32_PnPEntity (DeviceId) (VBOX)
- SELECT * FROM Win32_NetworkAdapterConfiguration (MACAddress) (VBOX)
- SELECT * FROM Win32_NTEventlogFile (VBOX)
- SELECT * FROM Win32_Processor (NumberOfCores) (GENERIC)
- SELECT * FROM Win32_LogicalDisk (Size) (GENERIC)
DLL Exports and Loaded DLLs
- kernel32.dll!wine_get_unix_file_nameWine (Wine)
- sbiedll.dll (Sandboxie)
- dbghelp.dll (MS debugging support routines)
- api_log.dll (iDefense Labs)
- dir_watch.dll (iDefense Labs)
- pstorec.dll (SunBelt Sandbox)
- vmcheck.dll (Virtual PC)
- wpespy.dll (WPE Pro)
- Hypervisor presence using (EAX=0x1)
- Hypervisor vendor using (EAX=0x40000000)
- "KVMKVMKVM\0\0\0" (KVM)
- "Microsoft Hv" (Microsoft Hyper-V or Windows Virtual PC)
- "VMwareVMware" (VMware)
- "XenVMMXenVMM" (Xen)
- "prl hyperv " ( Parallels) -"VBoxVBoxVBox" ( VirtualBox)
- OllyDBG / ImmunityDebugger / WinDbg / IDA Pro
- SysInternals Suite Tools (Process Explorer / Process Monitor / Regmon / Filemon, TCPView, Autoruns)
- Wireshark / Dumpcap
- ProcessHacker / SysAnalyzer / HookExplorer / SysInspector
- ImportREC / PETools / LordPE
- JoeBox Sandbox