diff --git a/docs/documentation.md b/docs/documentation.md index 91c8e8e0..137e7ba4 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -504,95 +504,95 @@ VMAware provides a convenient way to not only check for VMs, but also have the f | `VM::HYPERVISOR_BIT` | Check if hypervisor feature bit in CPUID eax bit 31 is enabled (always false for physical CPUs) | 🐧🪟🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L2278) | | `VM::HYPERVISOR_STR` | Check for hypervisor brand string length (would be around 2 characters in a host machine) | 🐧🪟🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L2299) | | `VM::TIMER` | Check for timing anomalies in the system | 🐧🪟🍏 | 55% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4378) | -| `VM::THREAD_COUNT` | Check if there are only 1 or 2 threads, which is a common pattern in VMs with default settings (nowadays physical CPUs should have at least 4 threads for modern CPUs | 🐧🪟🍏 | 35% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6618) | -| `VM::MAC` | Check if mac address starts with certain VM designated values | 🐧 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4663) | -| `VM::TEMPERATURE` | Check for device's temperature | 🐧 | 80% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5513) | -| `VM::SYSTEMD` | Check result from systemd-detect-virt tool | 🐧 | 35% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4544) | -| `VM::CVENDOR` | Check if the chassis vendor is a VM vendor | 🐧 | 65% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4568) | -| `VM::CTYPE` | Check if the chassis type is valid (it's very often invalid in VMs) | 🐧 | 20% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4593) | -| `VM::DOCKERENV` | Check if /.dockerenv or /.dockerinit file is present | 🐧 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4611) | -| `VM::DMIDECODE` | Check if dmidecode output matches a VM brand | 🐧 | 55% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4626) | -| `VM::DMESG` | Check if dmesg output matches a VM brand | 🐧 | 65% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4769) | -| `VM::HWMON` | Check if /sys/class/hwmon/ directory is present. If not, likely a VM | 🐧 | 35% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4810) | -| `VM::DLL` | Check for VM-specific DLLs | 🪟 | 50% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6914) | -| `VM::REGISTRY_KEYS` | Check for VM-specific registry keys | 🪟 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6945) | -| `VM::HWMODEL` | Check if the sysctl for the hwmodel does not contain the "Mac" string | 🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6642) | -| `VM::VBOX_DEFAULT` | Check for default RAM and DISK sizes set by VirtualBox | 🐧🪟 | 25% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5549) | -| `VM::WINE` | Check if the function "wine_get_unix_file_name" is present and if the OS booted from a VHD container | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7087) | -| `VM::POWER_CAPABILITIES` | Check what power states are enabled | 🪟 | 90% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7126) | -| `VM::PROCESSES` | Check for any VM processes that are active | 🐧 | 40% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5524) | -| `VM::LINUX_USER_HOST` | Check for default VM username and hostname for linux | 🐧 | 10% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4820) | -| `VM::GAMARUE` | Check for Gamarue ransomware technique which compares VM-specific Window product IDs | 🪟 | 10% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7205) | +| `VM::THREAD_COUNT` | Check if there are only 1 or 2 threads, which is a common pattern in VMs with default settings (nowadays physical CPUs should have at least 4 threads for modern CPUs | 🐧🪟🍏 | 35% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6584) | +| `VM::MAC` | Check if mac address starts with certain VM designated values | 🐧 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4629) | +| `VM::TEMPERATURE` | Check for device's temperature | 🐧 | 80% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5479) | +| `VM::SYSTEMD` | Check result from systemd-detect-virt tool | 🐧 | 35% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4510) | +| `VM::CVENDOR` | Check if the chassis vendor is a VM vendor | 🐧 | 65% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4534) | +| `VM::CTYPE` | Check if the chassis type is valid (it's very often invalid in VMs) | 🐧 | 20% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4559) | +| `VM::DOCKERENV` | Check if /.dockerenv or /.dockerinit file is present | 🐧 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4577) | +| `VM::DMIDECODE` | Check if dmidecode output matches a VM brand | 🐧 | 55% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4592) | +| `VM::DMESG` | Check if dmesg output matches a VM brand | 🐧 | 65% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4735) | +| `VM::HWMON` | Check if /sys/class/hwmon/ directory is present. If not, likely a VM | 🐧 | 35% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4776) | +| `VM::DLL` | Check for VM-specific DLLs | 🪟 | 50% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6880) | +| `VM::REGISTRY_KEYS` | Check for VM-specific registry keys | 🪟 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6911) | +| `VM::HWMODEL` | Check if the sysctl for the hwmodel does not contain the "Mac" string | 🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6608) | +| `VM::VBOX_DEFAULT` | Check for default RAM and DISK sizes set by VirtualBox | 🐧🪟 | 25% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5515) | +| `VM::WINE` | Check if the function "wine_get_unix_file_name" is present and if the OS booted from a VHD container | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7053) | +| `VM::POWER_CAPABILITIES` | Check what power states are enabled | 🪟 | 90% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7092) | +| `VM::PROCESSES` | Check for any VM processes that are active | 🐧 | 40% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5490) | +| `VM::LINUX_USER_HOST` | Check for default VM username and hostname for linux | 🐧 | 10% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4786) | +| `VM::GAMARUE` | Check for Gamarue ransomware technique which compares VM-specific Window product IDs | 🪟 | 10% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7171) | | `VM::BOCHS_CPU` | Check for various Bochs-related emulation oversights through CPU checks | 🐧🪟🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L2327) | -| `VM::MAC_MEMSIZE` | Check if memory is too low for MacOS system | 🍏 | 15% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6675) | -| `VM::MAC_IOKIT` | Check MacOS' IO kit registry for VM-specific strings | 🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6708) | -| `VM::IOREG_GREP` | Check for VM-strings in ioreg commands for MacOS | 🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6805) | -| `VM::MAC_SIP` | Check for the status of System Integrity Protection and hv_mm_present | 🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6862) | -| `VM::REGISTRY_VALUES` | Check HKLM registries for specific VM strings | 🪟 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7258) | -| `VM::VPC_INVALID` | Check for official VPC method | 🪟 | 75% | | 32-bit | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7392) | -| `VM::SIDT` | Check for uncommon IDT virtual addresses | 🐧🪟 | 50% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5673) | -| `VM::SGDT` | Check for sgdt instruction method | 🪟 | 50% | | | code documentation paper in /papers/www.offensivecomputing.net_vm.pdf (top-most byte signature) | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7446) | -| `VM::SLDT` | Check for sldt instruction method | 🪟 | 50% | | 32-bit | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7520) | -| `VM::SMSW` | Check for SMSW assembly instruction technique | 🪟 | 50% | | 32-bit | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7576) | -| `VM::VMWARE_IOMEM` | Check for VMware string in /proc/iomem | 🐧 | 65% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4849) | -| `VM::VMWARE_IOPORTS` | Check for VMware string in /proc/ioports | 🐧 | 70% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5359) | -| `VM::VMWARE_SCSI` | Check for VMware string in /proc/scsi/scsi | 🐧 | 40% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5158) | -| `VM::VMWARE_DMESG` | Check for VMware-specific device name in dmesg output | 🪟 | 65% | Admin | | Disabled by default | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5177) | -| `VM::VMWARE_STR` | Check str assembly instruction method for VMware | 🪟 | 35% | | 32-bit | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7605) | -| `VM::VMWARE_BACKDOOR` | Check for official VMware io port backdoor technique | 🪟 | 100% | | 32-bit | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7628) | -| `VM::MUTEX` | Check for mutex strings of VM brands | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7692) | +| `VM::MAC_MEMSIZE` | Check if memory is too low for MacOS system | 🍏 | 15% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6641) | +| `VM::MAC_IOKIT` | Check MacOS' IO kit registry for VM-specific strings | 🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6674) | +| `VM::IOREG_GREP` | Check for VM-strings in ioreg commands for MacOS | 🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6771) | +| `VM::MAC_SIP` | Check for the status of System Integrity Protection and hv_mm_present | 🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6828) | +| `VM::REGISTRY_VALUES` | Check HKLM registries for specific VM strings | 🪟 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7224) | +| `VM::VPC_INVALID` | Check for official VPC method | 🪟 | 75% | | 32-bit | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7358) | +| `VM::SIDT` | Check for uncommon IDT virtual addresses | 🐧🪟 | 50% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5639) | +| `VM::SGDT` | Check for sgdt instruction method | 🪟 | 50% | | | code documentation paper in /papers/www.offensivecomputing.net_vm.pdf (top-most byte signature) | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7412) | +| `VM::SLDT` | Check for sldt instruction method | 🪟 | 50% | | 32-bit | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7486) | +| `VM::SMSW` | Check for SMSW assembly instruction technique | 🪟 | 50% | | 32-bit | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7542) | +| `VM::VMWARE_IOMEM` | Check for VMware string in /proc/iomem | 🐧 | 65% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4815) | +| `VM::VMWARE_IOPORTS` | Check for VMware string in /proc/ioports | 🐧 | 70% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5325) | +| `VM::VMWARE_SCSI` | Check for VMware string in /proc/scsi/scsi | 🐧 | 40% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5124) | +| `VM::VMWARE_DMESG` | Check for VMware-specific device name in dmesg output | 🪟 | 65% | Admin | | Disabled by default | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5143) | +| `VM::VMWARE_STR` | Check str assembly instruction method for VMware | 🪟 | 35% | | 32-bit | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7571) | +| `VM::VMWARE_BACKDOOR` | Check for official VMware io port backdoor technique | 🪟 | 100% | | 32-bit | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7594) | +| `VM::MUTEX` | Check for mutex strings of VM brands | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7658) | | `VM::INTEL_THREAD_MISMATCH` | Check for Intel CPU thread count database if it matches the system's thread count | 🐧🪟🍏 | 50% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L2415) | | `VM::XEON_THREAD_MISMATCH` | Same as above, but for Xeon Intel CPUs | 🐧🪟🍏 | 50% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L3465) | | `VM::AMD_THREAD_MISMATCH` | Check for AMD CPU thread count database if it matches the system's thread count | 🐧🪟🍏 | 50% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L3679) | -| `VM::CUCKOO_DIR` | Check for cuckoo directory using crt and WIN API directory functions | 🪟 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7737) | -| `VM::CUCKOO_PIPE` | Check for Cuckoo specific piping mechanism | 🪟 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7755) | -| `VM::HYPERV_HOSTNAME` | Check for default Azure hostname format (Azure uses Hyper-V as their base VM brand) | 🐧🪟 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5783) | -| `VM::GENERAL_HOSTNAME` | Check for commonly set hostnames by certain VM brands | 🐧🪟 | 10% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5804) | -| `VM::DISPLAY` | Check for display configurations commonly found in VMs | 🪟 | 35% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7782) | -| `VM::DEVICE_STRING` | Check if bogus device string would be accepted | 🪟 | 25% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7833) | -| `VM::BLUESTACKS_FOLDERS` | Check for the presence of BlueStacks-specific folders | 🐧 | 5% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4865) | +| `VM::CUCKOO_DIR` | Check for cuckoo directory using crt and WIN API directory functions | 🪟 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7703) | +| `VM::CUCKOO_PIPE` | Check for Cuckoo specific piping mechanism | 🪟 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7721) | +| `VM::HYPERV_HOSTNAME` | Check for default Azure hostname format (Azure uses Hyper-V as their base VM brand) | 🐧🪟 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5749) | +| `VM::GENERAL_HOSTNAME` | Check for commonly set hostnames by certain VM brands | 🐧🪟 | 10% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5770) | +| `VM::DISPLAY` | Check for display configurations commonly found in VMs | 🪟 | 35% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7748) | +| `VM::DEVICE_STRING` | Check if bogus device string would be accepted | 🪟 | 25% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7799) | +| `VM::BLUESTACKS_FOLDERS` | Check for the presence of BlueStacks-specific folders | 🐧 | 5% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4831) | | `VM::CPUID_SIGNATURE` | Check for signatures in leaf 0x40000001 in CPUID | 🐧🪟🍏 | 95% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4325) | | `VM::KGT_SIGNATURE` | Check for Intel KGT (Trusty branch) hypervisor signature in CPUID | 🐧🪟🍏 | 80% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4354) | -| `VM::QEMU_VIRTUAL_DMI` | Check for presence of QEMU in the /sys/devices/virtual/dmi/id directory | 🐧 | 40% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4946) | -| `VM::QEMU_USB` | Check for presence of QEMU in the /sys/kernel/debug/usb/devices directory | 🐧 | 20% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4975) | -| `VM::HYPERVISOR_DIR` | Check for presence of any files in /sys/hypervisor directory | 🐧 | 20% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5003) | -| `VM::UML_CPU` | Check for the "UML" string in the CPU brand | 🐧 | 80% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5051) | -| `VM::KMSG` | Check for any indications of hypervisors in the kernel message logs | 🐧 | 5% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5081) | -| `VM::VBOX_MODULE` | Check for a VBox kernel module | 🐧 | 15% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5135) | -| `VM::SYSINFO_PROC` | Check for potential VM info in /proc/sysinfo | 🐧 | 15% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5211) | -| `VM::DMI_SCAN` | Check for string matches of VM brands in the linux DMI | 🐧 | 50% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5233) | -| `VM::SMBIOS_VM_BIT` | Check for the VM bit in the SMBIOS data | 🐧 | 50% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5314) | -| `VM::PODMAN_FILE` | Check for podman file in /run/ | 🐧 | 5% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5344) | -| `VM::WSL_PROC` | Check for WSL or microsoft indications in /proc/ subdirectories | 🐧 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5376) | -| `VM::DRIVERS` | Check for VM-specific names for drivers | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7850) | -| `VM::DISK_SERIAL` | Check for serial numbers of virtual disks | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7956) | -| `VM::IVSHMEM` | Check for IVSHMEM device presence | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8126) | -| `VM::GPU_CAPABILITIES` | Check for GPU capabilities related to VMs | 🪟 | 45% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8173) | -| `VM::DEVICE_HANDLES` | Check for vm-specific devices | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8211) | -| `VM::QEMU_FW_CFG` | Detect QEMU fw_cfg interface. This first checks the Device Tree for a fw-cfg node or hypervisor tag, then verifies the presence of the qemu_fw_cfg module and firmware directories in sysfs. | 🐧 | 70% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5404) | -| `VM::VIRTUAL_PROCESSORS` | Check if the number of virtual and logical processors are reported correctly by the system | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8264) | -| `VM::HYPERV_QUERY` | Check if a call to NtQuerySystemInformation with the 0x9f leaf fills a _SYSTEM_HYPERVISOR_DETAIL_INFORMATION structure | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8294) | -| `VM::AMD_SEV` | Check for AMD-SEV MSR running on the system | 🐧🍏 | 50% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4888) | -| `VM::VIRTUAL_REGISTRY` | Check for particular object directory which is present in Sandboxie virtual environment but not in usual host systems | 🪟 | 90% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8353) | -| `VM::FIRMWARE` | Check for VM signatures on all firmware tables | 🐧🪟 | 100% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5836) | -| `VM::FILE_ACCESS_HISTORY` | Check if the number of accessed files are too low for a human-managed environment | 🐧 | 15% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5434) | -| `VM::AUDIO` | Check if no waveform-audio output devices are present in the system | 🪟 | 25% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8442) | -| `VM::NSJAIL_PID` | Check if process status matches with nsjail patterns with PID anomalies | 🐧 | 75% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5461) | -| `VM::TPM` | Check if the system has a physical TPM by matching the TPM manufacturer against known physical TPM chip vendors | 🪟 | 100% | | | CRB model will succeed, while TIS will fail | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8484) | -| `VM::PCI_DEVICES` | Check for PCI vendor and device IDs that are VM-specific | 🐧🪟 | 95% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6265) | -| `VM::ACPI_SIGNATURE` | Check for VM-specific ACPI device signatures | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8596) | -| `VM::TRAP` | Check if after raising two traps at the same RIP, a hypervisor interferes with the instruction pointer delivery | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8779) | -| `VM::UD` | Check if after executing an undefined instruction, a hypervisor misinterpret it as a system call | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8877) | -| `VM::BLOCKSTEP` | Check if a hypervisor does not properly restore the interruptibility state after a VM-exit in compatibility mode | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8935) | -| `VM::DBVM` | Check if Dark Byte's VM is present | 🪟 | 150% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8982) | -| `VM::BOOT_LOGO` | Check boot logo for known VM images | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9072) | -| `VM::MAC_SYS` | Check for VM-strings in system profiler commands for MacOS | 🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6889) | -| `VM::OBJECTS` | Check for known VM objects | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9165) | -| `VM::NVRAM` | Check for known NVRAM signatures that are present on virtual firmware | 🪟 | 100% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9356) | -| `VM::BOOT_MANAGER` | Check for boot managers typically found in VMs | 🪟 | 50% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9593) | -| `VM::SMBIOS_INTEGRITY` | Check if SMBIOS is malformed/corrupted in a way that is typical for VMs | 🪟 | 60% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9793) | -| `VM::EDID` | Check for non-standard EDID configurations | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9804) | -| `VM::CPU_HEURISTIC` | Check if the CPU is capable of running certain instructions successfully | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9913) | +| `VM::QEMU_VIRTUAL_DMI` | Check for presence of QEMU in the /sys/devices/virtual/dmi/id directory | 🐧 | 40% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4912) | +| `VM::QEMU_USB` | Check for presence of QEMU in the /sys/kernel/debug/usb/devices directory | 🐧 | 20% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4941) | +| `VM::HYPERVISOR_DIR` | Check for presence of any files in /sys/hypervisor directory | 🐧 | 20% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4969) | +| `VM::UML_CPU` | Check for the "UML" string in the CPU brand | 🐧 | 80% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5017) | +| `VM::KMSG` | Check for any indications of hypervisors in the kernel message logs | 🐧 | 5% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5047) | +| `VM::VBOX_MODULE` | Check for a VBox kernel module | 🐧 | 15% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5101) | +| `VM::SYSINFO_PROC` | Check for potential VM info in /proc/sysinfo | 🐧 | 15% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5177) | +| `VM::DMI_SCAN` | Check for string matches of VM brands in the linux DMI | 🐧 | 50% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5199) | +| `VM::SMBIOS_VM_BIT` | Check for the VM bit in the SMBIOS data | 🐧 | 50% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5280) | +| `VM::PODMAN_FILE` | Check for podman file in /run/ | 🐧 | 5% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5310) | +| `VM::WSL_PROC` | Check for WSL or microsoft indications in /proc/ subdirectories | 🐧 | 30% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5342) | +| `VM::DRIVERS` | Check for VM-specific names for drivers | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7816) | +| `VM::DISK_SERIAL` | Check for serial numbers of virtual disks | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L7922) | +| `VM::IVSHMEM` | Check for IVSHMEM device presence | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8092) | +| `VM::GPU_CAPABILITIES` | Check for GPU capabilities related to VMs | 🪟 | 45% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8139) | +| `VM::DEVICE_HANDLES` | Check for vm-specific devices | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8177) | +| `VM::QEMU_FW_CFG` | Detect QEMU fw_cfg interface. This first checks the Device Tree for a fw-cfg node or hypervisor tag, then verifies the presence of the qemu_fw_cfg module and firmware directories in sysfs. | 🐧 | 70% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5370) | +| `VM::VIRTUAL_PROCESSORS` | Check if the number of virtual and logical processors are reported correctly by the system | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8230) | +| `VM::HYPERV_QUERY` | Check if a call to NtQuerySystemInformation with the 0x9f leaf fills a _SYSTEM_HYPERVISOR_DETAIL_INFORMATION structure | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8260) | +| `VM::AMD_SEV` | Check for AMD-SEV MSR running on the system | 🐧🍏 | 50% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L4854) | +| `VM::VIRTUAL_REGISTRY` | Check for particular object directory which is present in Sandboxie virtual environment but not in usual host systems | 🪟 | 90% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8319) | +| `VM::FIRMWARE` | Check for VM signatures on all firmware tables | 🐧🪟 | 100% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5802) | +| `VM::FILE_ACCESS_HISTORY` | Check if the number of accessed files are too low for a human-managed environment | 🐧 | 15% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5400) | +| `VM::AUDIO` | Check if no waveform-audio output devices are present in the system | 🪟 | 25% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8408) | +| `VM::NSJAIL_PID` | Check if process status matches with nsjail patterns with PID anomalies | 🐧 | 75% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L5427) | +| `VM::PCI_DEVICES` | Check for PCI vendor and device IDs that are VM-specific | 🐧🪟 | 95% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6231) | +| `VM::ACPI_SIGNATURE` | Check for VM-specific ACPI device signatures | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8449) | +| `VM::TRAP` | Check if after raising two traps at the same RIP, a hypervisor interferes with the instruction pointer delivery | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8632) | +| `VM::UD` | Check if after executing an undefined instruction, a hypervisor misinterpret it as a system call | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8737) | +| `VM::BLOCKSTEP` | Check if a hypervisor does not properly restore the interruptibility state after a VM-exit in compatibility mode | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8803) | +| `VM::DBVM` | Check if Dark Byte's VM is present | 🪟 | 150% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8850) | +| `VM::BOOT_LOGO` | Check boot logo for known VM images | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L8947) | +| `VM::MAC_SYS` | Check for VM-strings in system profiler commands for MacOS | 🍏 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L6855) | +| `VM::OBJECTS` | Check for known VM objects | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9040) | +| `VM::NVRAM` | Check for known NVRAM signatures that are present on virtual firmware | 🪟 | 100% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9231) | +| `VM::BOOT_MANAGER` | Check for boot managers typically found in VMs | 🪟 | 50% | Admin | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9468) | +| `VM::SMBIOS_INTEGRITY` | Check if SMBIOS is malformed/corrupted in a way that is typical for VMs | 🪟 | 60% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9668) | +| `VM::EDID` | Check for non-standard EDID configurations | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9679) | +| `VM::CPU_HEURISTIC` | Check if the CPU is capable of running certain instructions successfully | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9788) | +| `VM::CLOCK` | Check the presence of system timers | 🪟 | 100% | | | | [link](https://github.com/kernelwernel/VMAware/tree/main/src/vmaware.hpp#L9983) | diff --git a/src/cli.cpp b/src/cli.cpp index 55ce4b6e..45d88a04 100755 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -819,7 +819,6 @@ static void general() { checker(VM::FIRMWARE, "firmware"); checker(VM::FILE_ACCESS_HISTORY, "low file access count"); checker(VM::NSJAIL_PID, "nsjail PID"); - checker(VM::TPM, "TPM manufacturer"); checker(VM::PCI_DEVICES, "PCI vendor/device ID"); checker(VM::ACPI_SIGNATURE, "ACPI device signatures"); checker(VM::TRAP, "hypervisor interception"); @@ -834,7 +833,7 @@ static void general() { checker(VM::SMBIOS_INTEGRITY, "SMBIOS integrity"); checker(VM::EDID, "EDID"); checker(VM::CPU_HEURISTIC, "CPU heuristics"); - + checker(VM::CLOCK, "system timers"); // ADD NEW TECHNIQUE CHECKER HERE const auto t2 = std::chrono::high_resolution_clock::now(); diff --git a/src/vmaware.hpp b/src/vmaware.hpp index 17815546..4853f177 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -56,10 +56,10 @@ * - struct for internal cpu operations => line 720 * - struct for internal memoization => line 1095 * - struct for internal utility functions => line 1225 - * - struct for internal core components => line 10102 + * - struct for internal core components => line 10081 * - start of VM detection technique list => line 2181 - * - start of public VM detection functions => line 10595 - * - start of externally defined variables => line 11579 + * - start of public VM detection functions => line 10574 + * - start of externally defined variables => line 11558 * * * ============================== EXAMPLE =================================== @@ -535,7 +535,6 @@ struct VM { enum enum_flags : u8 { // Windows GPU_CAPABILITIES = 0, - TPM, ACPI_SIGNATURE, POWER_CAPABILITIES, DISK_SERIAL, @@ -573,6 +572,7 @@ struct VM { SMBIOS_INTEGRITY, EDID, CPU_HEURISTIC, + CLOCK, // Linux and Windows SIDT, @@ -4392,12 +4392,12 @@ struct VM { // Case A - Hypervisor without RDTSC patch static unsigned aux = 0; - // Check for RDTSC support + // Check for RDTSCP support { #if (x86_64 && WINDOWS) const bool haveRdtscp = [&]() noexcept -> bool { __try { - __rdtscp(&aux); // check for RDTSCP support as we will use it later + __rdtscp(&aux); return true; } __except (EXCEPTION_EXECUTE_HANDLER) { @@ -4449,11 +4449,11 @@ struct VM { // calculates the invariant TSC base rate, not the dynamic core frequency, similar to what CallNtPowerInformation would give you LARGE_INTEGER t1q, t2q; - u64 t1 = __rdtsc(); + const u64 t1 = __rdtsc(); QueryPerformanceCounter(&t1q); // uses RDTSCP under the hood unless platformclock (a bcdedit setting) is set, which then would use HPET or ACPI PM via NtQueryPerformanceCounter SleepEx(50, 0); QueryPerformanceCounter(&t2q); - u64 t2 = __rdtsc(); + const u64 t2 = __rdtsc(); const double elapsedSec = double(t2q.QuadPart - t1q.QuadPart) / double(freq.QuadPart); // the performance counter frequency is always 10MHz when running under Hyper-V const double tscHz = double(t2 - t1) / elapsedSec; @@ -4461,7 +4461,7 @@ struct VM { debug("TIMER: Current CPU base speed -> ", tscMHz, " MHz"); - if (tscMHz < 1000.00) return true; + if (tscMHz < 1000.0) return true; const struct cpu::stepping_struct steps = cpu::fetch_steppings(); const u32 baseMHz = cpu::get_cpu_base_speed(); // wont probably work reliably on AMD, but its more reliable than fetching from SMBIOS @@ -4469,12 +4469,16 @@ struct VM { if (baseMHz == 0) { debug("TIMER: Processor base speed not available for this processor"); } - else if (baseMHz < 1000.00) { + else if (baseMHz < 1000.0) { return true; } + else { + debug("TIMER: Processor base speed -> ", static_cast(baseMHz), " MHz"); + if (tscMHz <= static_cast(baseMHz) - 100.0) { + return true; + } + } - debug("TIMER: Processor base speed -> ", static_cast(baseMHz), " MHz"); - // Case C - Hypervisor with RDTSC patch + useplatformclock = false ULONGLONG time1 = 0; const ULONGLONG tsc1 = __rdtsc(); @@ -4488,55 +4492,17 @@ struct VM { const ULONGLONG delta_time = time2 - time1; // 100 ns const ULONGLONG delta_tsc = tsc2 - tsc1; // cycles - - debug("TIMER: Interrupt -> ", delta_time, ", RDTSC -> ", delta_tsc); - if (delta_time == 0) return false; - + if (delta_time == 0) return false; const double interrupt_ratio = static_cast(delta_tsc) / static_cast(delta_time); - if (interrupt_ratio < 200.0) return true; - - if (cycleThreshold == 25000) return false; // if we're running under Hyper-V, do not continue - - const int TRIALS = 20; // enough to warm up the syscall path, higher values will hardly evict spikes - std::vector ratios; - ratios.reserve(TRIALS); - - for (int i = 0; i < TRIALS; ++i) { - t1 = __rdtscp(&aux); // serializing to avoid speculative execution, which would increase the ratio - GetProcessHeap(); // user-mode call - t2 = __rdtscp(&aux); - - // some hypervisors like DBVM will add a low base value + some random tsc value if the difference between tsc reads is less than 4000 cycles or so - // this could be handled by doing something like for (int i = 0; i < AGG; ++i) CloseHandle(INVALID_HANDLE_VALUE); or sleeping the thread to induce cache flushing - // so the measured syscall time > hypervisor patch window, but its not an elegant solution at all - CloseHandle(INVALID_HANDLE_VALUE); // kernel syscall - const u64 t3 = __rdtscp(&aux); // on modern Intel and AMD CPUs the TSC is "invariant" (doesn't change with P-states or C-states) - - // older chips often lack an invariant TSC and can be queried in CPUID 0x80000007 EDX[8], the medians should be larger but if they are larger they won't produce false flags - - // important to not debug cycles by printing but with breakpoints and stack analysis, otherwise the CPU would cache and make the ratio much lower - const u64 userCycles = t2 - t1; - const u64 sysCycles = t3 - t2; - if (userCycles == 0) - continue; - - const double ratio = static_cast(sysCycles) / static_cast(userCycles); - ratios.push_back(ratio); - } - - if (ratios.empty()) return false; - std::sort(ratios.begin(), ratios.end()); - const double tscMedian = ratios[ratios.size() / 2]; // to minimize jittering due to kernel noise - debug("TIMER: Median syscall/user-mode ratio -> ", tscMedian); - if (tscMedian < 6.5) return true; // < on purpose + debug("TIMER: Interrupt -> ", delta_time, ", RDTSC -> ", delta_tsc, ", Ratio -> ", interrupt_ratio); + if (interrupt_ratio < 200.0) return true; // TLB flushes or side channel cache attacks are not even tried due to how ineffective they are against stealthy hypervisors #endif return false; #endif } - #if (LINUX) /** * @brief Check result from systemd-detect-virt tool @@ -8477,119 +8443,6 @@ struct VM { } - /** - * @brief Check if the system has a physical TPM by matching the TPM manufacturer against known physical TPM chip vendors - * @category Windows - * @note CRB model will succeed, while TIS will fail - * @implements VM::TPM - */ - [[nodiscard]] static bool tpm() { - if (util::is_running_under_translator()) { - return false; - } - struct TbsContext { - TBS_HCONTEXT hContext = 0; - - explicit TbsContext(const TBS_CONTEXT_PARAMS2& params) { - TBS_RESULT res = Tbsi_Context_Create( - reinterpret_cast(¶ms), - &hContext); - if (res != TBS_SUCCESS) { - hContext = 0; - } - } - - ~TbsContext() { - if (hContext) { - Tbsip_Context_Close(hContext); - } - } - - // non-copyable - TbsContext(const TbsContext&) = delete; - TbsContext& operator=(const TbsContext&) = delete; - - // movable - TbsContext(TbsContext&& o) noexcept : hContext(o.hContext) { o.hContext = 0; } - TbsContext& operator=(TbsContext&& o) noexcept { - if (this != &o) { - if (hContext) Tbsip_Context_Close(hContext); - hContext = o.hContext; - o.hContext = 0; - } - return *this; - } - - bool isValid() const { return hContext != 0; } - }; - - TBS_CONTEXT_PARAMS2 params{}; - params.version = TBS_CONTEXT_VERSION_TWO; - params.includeTpm20 = 1; - params.includeTpm12 = 1; - - TbsContext ctx(params); - if (!ctx.isValid()) { - return false; - } - - // TPM2_GetCapability command for TPM_PT_MANUFACTURER - static constexpr u8 cmd[] = { - 0x80,0x01, // Tag: TPM_ST_NO_SESSIONS - 0x00,0x00,0x00,0x16, // Command Size: 22 - 0x00,0x00,0x01,0x7A, // TPM2_GetCapability - 0x00,0x00,0x00,0x06, // TPM_CAP_TPM_PROPERTIES - 0x00,0x00,0x01,0x05, // TPM_PT_MANUFACTURER - 0x00,0x00,0x00,0x01 // Property Count: 1 - }; - - u8 resp[64] = {}; - u32 respSize = static_cast(sizeof(resp)); - TBS_RESULT submitRes = Tbsip_Submit_Command( - ctx.hContext, - TBS_COMMAND_LOCALITY_ZERO, - TBS_COMMAND_PRIORITY_NORMAL, - cmd, - static_cast(sizeof(cmd)), - resp, - &respSize); - - if (submitRes != TBS_SUCCESS || respSize < 27) { - return false; - } - - const u32 tpm = (static_cast(resp[23]) << 24) | (static_cast(resp[24]) << 16) | - (static_cast(resp[25]) << 8) | static_cast(resp[26]); - - if (tpm == 0) { - return false; - } - - debug("TPM: Manufacturer -> 0x", std::hex, tpm); - - switch (tpm) { - case 0x414D4400u: // "AMD\0" - case 0x41544D4Cu: // "ATML" - case 0x4252434Du: // "BRCM" - case 0x49424D00u: // "IBM\0" (used by VirtualBox) - case 0x49465800u: // "IFX\0" - case 0x494E5443u: // "INTC" - case 0x4E534D20u: // "NSM " - case 0x4E544300u: // "NTC\0" - case 0x51434F4Du: // "QCOM" - case 0x534D5343u: // "SMSC" - case 0x53544D20u: // "STM " - case 0x54584E00u: // "TXN\0" - case 0x524F4343u: // "ROCC" - case 0x4C454E00u: // "LEN\0" - // case 0x4d534654u: // "MSFT" (used in ARM devices and Hyper-V VMs) - return false; - default: - return true; - } - } - - /** * @brief Check for VM-specific ACPI device signatures * @category Windows @@ -8780,7 +8633,7 @@ struct VM { */ [[nodiscard]] static bool trap() { bool hypervisorCaught = false; - #if (x86) +#if (x86) // when a single-step (TF) and hardware breakpoint (DR0) collide, Intel CPUs set both DR6.BS and DR6.B0 to report both events, which help make this detection trick // AMD CPUs prioritize the breakpoint, setting only its corresponding bit in DR6 and clearing the single-step bit, which is why this technique is not compatible with AMD if (!cpu::is_intel()) { @@ -8802,12 +8655,19 @@ struct VM { // simple way to support x86 without recurring to inline assembly void* execMem = VirtualAlloc(nullptr, trampSize, MEM_COMMIT | MEM_RESERVE, - PAGE_EXECUTE_READWRITE); + PAGE_READWRITE); if (!execMem) { return false; } memcpy(execMem, trampoline, trampSize); + DWORD oldProtect = 0; + if (!VirtualProtect(execMem, trampSize, PAGE_EXECUTE_READ, &oldProtect)) { + VirtualFree(execMem, 0, MEM_RELEASE); + return false; + } + FlushInstructionCache(GetCurrentProcess(), execMem, trampSize); + int hitCount = 0; // save original debug registers @@ -8866,7 +8726,7 @@ struct VM { SetThreadContext(thr, &origCtx); VirtualFree(execMem, 0, MEM_RELEASE); - #endif +#endif return hypervisorCaught; } @@ -8893,38 +8753,46 @@ struct VM { #else // architecture not supported by this check return false; - #endif + #endif - void* stub = nullptr; + void* stub = nullptr; - __try { - stub = VirtualAlloc(nullptr, sizeof(ud_opcodes), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (!stub) { - __leave; - } + __try { + stub = VirtualAlloc(nullptr, sizeof(ud_opcodes), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (!stub) { + __leave; + } - memcpy(stub, ud_opcodes, sizeof(ud_opcodes)); + memcpy(stub, ud_opcodes, sizeof(ud_opcodes)); - // the instruction cache must be flushed after writing code to memory on ARM - #if (ARM) - FlushInstructionCache(GetCurrentProcess(), stub, sizeof(ud_opcodes)); - #endif - __try { - reinterpret_cast(stub)(); - } - __except (GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION - ? EXCEPTION_EXECUTE_HANDLER - : EXCEPTION_CONTINUE_SEARCH) - { - saw_ud = true; - } + DWORD oldProtect = 0; + if (!VirtualProtect(stub, sizeof(ud_opcodes), PAGE_EXECUTE_READ, &oldProtect)) { + __leave; } - __finally { - if (stub) { - VirtualFree(stub, 0, MEM_RELEASE); - } + + // the instruction cache must be flushed after writing code to memory on ARM + #if (ARM) + FlushInstructionCache(GetCurrentProcess(), stub, sizeof(ud_opcodes)); + #else + FlushInstructionCache(GetCurrentProcess(), stub, sizeof(ud_opcodes)); + #endif + + __try { + reinterpret_cast(stub)(); } - #endif + __except (GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION + ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH) + { + saw_ud = true; + } + } + __finally { + if (stub) { + VirtualFree(stub, 0, MEM_RELEASE); + } + } +#endif return !saw_ud; } @@ -9018,11 +8886,14 @@ struct VM { constexpr SIZE_T stubSize = 44; const bool isAmd = cpu::is_amd(); - void* stub = VirtualAlloc(nullptr, stubSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + + // allocate RW memory so we can write template + immediates + void* stub = VirtualAlloc(nullptr, stubSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!stub) { return false; } + // copy the template while writable if (isAmd) { memcpy(stub, amdTemplate, stubSize); } @@ -9030,12 +8901,20 @@ struct VM { memcpy(stub, intelTemplate, stubSize); } - // patch in the immediate values (PW1, PW3, &vmcallInfo, &vmcallResult) at the correct offsets: + // patch in the immediate values *reinterpret_cast(reinterpret_cast(stub) + 2) = PW1; *reinterpret_cast(reinterpret_cast(stub) + 12) = PW3; *reinterpret_cast(reinterpret_cast(stub) + 22) = reinterpret_cast(static_cast(&vmcallInfo)); *reinterpret_cast(reinterpret_cast(stub) + 35) = reinterpret_cast(static_cast(&vmcallResult)); + DWORD oldProtect = 0; + if (!VirtualProtect(stub, stubSize, PAGE_EXECUTE_READ, &oldProtect)) { + VirtualFree(stub, 0, MEM_RELEASE); + return false; + } + + FlushInstructionCache(GetCurrentProcess(), stub, stubSize); + // lambda that executes the stub (Intel or AMD) and checks for the CE signature auto tryPass = [&]() -> bool { vmcallInfo.structsize = static_cast(sizeof(VMCallInfo)); @@ -9918,12 +9797,18 @@ struct VM { // 1.1 - Test RDPID EAX); C3 (RET) const unsigned char code[] = { 0xF3, 0x0F, 0xC7, 0xF8, 0xC3 }; - void* mem = VirtualAlloc(NULL, sizeof(code), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + void* mem = VirtualAlloc(NULL, sizeof(code), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!mem) { return false; } memcpy(mem, code, sizeof(code)); + + DWORD oldProtect = 0; + if (!VirtualProtect(mem, sizeof(code), PAGE_EXECUTE_READ, &oldProtect)) { + VirtualFree(mem, 0, MEM_RELEASE); + return false; + } if (!FlushInstructionCache(GetCurrentProcess(), mem, sizeof(code))) { VirtualFree(mem, 0, MEM_RELEASE); return false; @@ -9934,7 +9819,7 @@ struct VM { bool ok = true; __try { - u64 val = fn(); + (void)fn(); } __except (GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ? EXCEPTION_EXECUTE_HANDLER @@ -10043,13 +9928,18 @@ struct VM { } if (proceed) { - exec_mem = VirtualAlloc(NULL, codeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + exec_mem = VirtualAlloc(NULL, codeSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (exec_mem == NULL) { proceed = false; } else { memcpy(exec_mem, bytes, codeSize); - if (!FlushInstructionCache(GetCurrentProcess(), exec_mem, codeSize)) { + + DWORD oldProtectExec = 0; + if (!VirtualProtect(exec_mem, codeSize, PAGE_EXECUTE_READ, &oldProtectExec)) { + proceed = false; + } + else if (!FlushInstructionCache(GetCurrentProcess(), exec_mem, codeSize)) { proceed = false; } else { @@ -10068,7 +9958,7 @@ struct VM { const int runner_rc = runner(reinterpret_cast(exec_mem)); if (runner_rc == 0 && exception) { debug("CPU_HEURISTIC: CPU reports being Intel, but VMAware detected a hypervisor running an AMD CPU in the host"); // or another CPU - spoofed = true; + spoofed = true; } else if (runner_rc == 1 && !exception) { debug("CPU_HEURISTIC: CPU reports being AMD, but VMAware detected a hypervisor running an Intel CPU in the host"); // or another CPU @@ -10089,6 +9979,99 @@ struct VM { return spoofed; } + + + /** + * @brief Check the presence of system timers + * @category Windows + * @implements VM::CLOCK + */ + [[nodiscard]] static bool clock() { + // The RTC (ACPI/CMOS RTC) timer can't be always detected via SetupAPI, it needs AML decode of the DSDT firmware table. + // The HPET (PNP0103) timer presence is already checked on VM::FIRMWARE + constexpr wchar_t pattern[] = L"PNP0100"; + constexpr size_t patLen = (sizeof(pattern) / sizeof(wchar_t)) - 1; + + auto tolower_ascii = [](wchar_t c) -> wchar_t { + return (c >= L'A' && c <= L'Z') ? static_cast(c + 32) : c; + }; + + auto wcsstr_ci_ascii = [&](const wchar_t* hay) -> const wchar_t* { + if (!hay) return nullptr; + for (; *hay; ++hay) { + wchar_t h0 = tolower_ascii(*hay); + wchar_t p0 = tolower_ascii(pattern[0]); + if (h0 != p0) continue; + + const wchar_t* h = hay; + size_t i = 0; + for (; i < patLen; ++i, ++h) { + if (*h == L'\0') { i = SIZE_MAX; break; } + if (tolower_ascii(*h) != tolower_ascii(pattern[i])) break; + } + if (i == patLen) return hay; // match + if (i == SIZE_MAX) return nullptr; + } + return nullptr; + }; + + HDEVINFO devs = SetupDiGetClassDevsW(nullptr, nullptr, nullptr, DIGCF_PRESENT); + if (devs == INVALID_HANDLE_VALUE) return false; + + SP_DEVINFO_DATA devInfo{}; + devInfo.cbSize = sizeof(SP_DEVINFO_DATA); + + DWORD bufBytes = 4096; + BYTE* buffer = static_cast(malloc(bufBytes)); + if (!buffer) { + SetupDiDestroyDeviceInfoList(devs); + return false; + } + + bool found = false; + for (DWORD idx = 0; SetupDiEnumDeviceInfo(devs, idx, &devInfo); ++idx) { + DWORD propertyType = 0; + if (!SetupDiGetDeviceRegistryPropertyW(devs, &devInfo, SPDRP_HARDWAREID, + &propertyType, buffer, bufBytes, nullptr)) + { + DWORD err = GetLastError(); + if (err == ERROR_INSUFFICIENT_BUFFER) { + DWORD required = 0; + SetupDiGetDeviceRegistryPropertyW(devs, &devInfo, SPDRP_HARDWAREID, + &propertyType, nullptr, 0, &required); + if (required > bufBytes) { + BYTE* newBuf = static_cast(realloc(buffer, required)); + if (!newBuf) { found = false; break; } + buffer = newBuf; + bufBytes = required; + } + if (!SetupDiGetDeviceRegistryPropertyW(devs, &devInfo, SPDRP_HARDWAREID, + &propertyType, buffer, bufBytes, nullptr)) { + continue; + } + } + else { + continue; + } + } + + if (propertyType != REG_MULTI_SZ) continue; + + wchar_t* cur = reinterpret_cast(buffer); + while (*cur) { + if (wcsstr_ci_ascii(cur)) { + found = true; + break; + } + cur += wcslen(cur) + 1; + } + if (found) break; + } + + free(buffer); + SetupDiDestroyDeviceInfoList(devs); + return !found; + } // ADD NEW TECHNIQUE FUNCTION HERE #endif @@ -11168,7 +11151,6 @@ struct VM { case FILE_ACCESS_HISTORY: return "FILE_ACCESS_HISTORY"; case AUDIO: return "AUDIO"; case NSJAIL_PID: return "NSJAIL_PID"; - case TPM: return "TPM"; case PCI_DEVICES: return "PCI_DEVICES"; case ACPI_SIGNATURE: return "ACPI_SIGNATURE"; case TRAP: return "TRAP"; @@ -11183,6 +11165,7 @@ struct VM { case SMBIOS_INTEGRITY: return "SMBIOS_INTEGRITY"; case EDID: return "EDID"; case CPU_HEURISTIC: return "CPU_HEURISTIC"; + case CLOCK: return "CLOCK"; // END OF TECHNIQUE LIST case DEFAULT: return "setting flag, error"; case ALL: return "setting flag, error"; @@ -11718,13 +11701,13 @@ std::pair VM::core::technique_list[] = { std::make_pair(VM::TRAP, VM::core::technique(100, VM::trap)), std::make_pair(VM::ACPI_SIGNATURE, VM::core::technique(100, VM::acpi_signature)), std::make_pair(VM::NVRAM, VM::core::technique(100, VM::nvram_vars)), + std::make_pair(VM::CLOCK, VM::core::technique(100, VM::clock)), std::make_pair(VM::BOOT_MANAGER, VM::core::technique(50, VM::nvram_boot)), std::make_pair(VM::POWER_CAPABILITIES, VM::core::technique(90, VM::power_capabilities)), std::make_pair(VM::CPU_HEURISTIC, VM::core::technique(100, VM::cpu_heuristic)), std::make_pair(VM::EDID, VM::core::technique(100, VM::edid)), std::make_pair(VM::BOOT_LOGO, VM::core::technique(100, VM::boot_logo)), std::make_pair(VM::GPU_CAPABILITIES, VM::core::technique(45, VM::gpu_capabilities)), - std::make_pair(VM::TPM, VM::core::technique(100, VM::tpm)), std::make_pair(VM::SMBIOS_INTEGRITY, VM::core::technique(60, VM::smbios_integrity)), std::make_pair(VM::DISK_SERIAL, VM::core::technique(100, VM::disk_serial_number)), std::make_pair(VM::IVSHMEM, VM::core::technique(100, VM::ivshmem)),