Recently, I built a new desktop computer, since Covid-19 has dictated that my upcoming Fall semester will be entirely held online. You can read more about the set-up in an upcoming post, but the long and short of it is that I went with an AMD build geared around hosting a homelab through KVM/QEMU/libvirt virtualization. I also passed through a dedicated RTX 2070s for gaming in a Windows 10 VM. This presented a problem: some anti-cheat software is hostile to virtualized environments and will kick or even ban you for playing online in a virtual machine. See this tweet from BattlEye, the most recent AC to take a directly hostile stance towards VM gaming.
Now, there is a whole argument going on about the veracity of the numbers that BattlEye claims. They are almost certainly lumping attempts at evading the VM detection together with actual cheating. A large chunk of VFIO gamers, myself included, are required to do rudimentary detection evasion to get certain drivers to work (error 43). They also failed to mention any intention of leveraging new technologies like AMD’s SEV-ES for verifying the integrity of memory.
For someone like myself who has zero interest in installing Windows natively, the only option to play certain games is to try to hide the fact that the machine is virtualized. Before we begin, I have a disclaimer for anyone wanting to follow in my footsteps: it is always going to be easier to detect a vm than to hide it. Researchers can only patch VM detection methods reflexively. There are many differernt approaches to detecting a sandboxed environment and if you use the following methods to evade detection by anti-cheat, odds are good that they will eventually update their detection methods and you will have accounts banned. I also want to make it clear that I am not an expert. These methods were aggregated from various sources on the internet and I am simply documenting my experience (for myself because no-one reads this lol).
I was inspired by this reddit post and am using the anti-detection methods mentioned there and piecemealed from elsewhere on the internet.
The Kernel - intercepting RDTSC exit calls
Recently a patch for the 5.7.11 kernel was released that intercepts RDTSC cpu exit calls. This github repo has the patch for 5.7.11, but I’m on 5.8.1, so instead of downgrading the kernel I updated the patch which can be found here. It seems to work fine on the updated kernel version.
Grab the 5.8.1 linux kernel source code:
xz -d linux-5.7.15.tar.xz
gpg --verify linux-5.7.15.tar.sign
tar -xvf linux-5.8.1.tar
Use Arch default
zcat /proc/config.gz > .config
Copy the kernel to /boot:
cp -v arch/x86_64/boot/bzImage /boot/vmlinuz-linux58-patched
Make initial ram disk using an edited mkinitcpio preset:
cp /etc/mkinitcpio.d/linux.preset /etc/mkinitcpio.d/linux58-patched.preset vim /etc/mkinitcpio.d/linux58-patched.preset # <--change img names here to match new kernel mkinitcpio -p linux58-patched
Update GRUB config:
grub-mkconfig -o /boot/grub/grub.cfg
Reboot the system and verify that your vm boots properly.
Paranoid Fish (pafish) is “a demonstration tool that employs several techniques to detect sandboxes and analysis environments in the same way as malware families do”. Check out the projects github repo for more info.
Before KVM RDTSC patch
After KVM RDTSC patch
We can also quickly get rid of the CPUID hypervisor feature bit with
<feature policy='disable' name='hypervisor'/>. Note you will see a performance because you no-longer get hyperv enlightenments in your guest.
- KVM CPUID bits
- A good description of CPU pinning
- tsc timer passthrough (This might only work on intel chips, vm fails to boot on my setup)
- sed fun facts
- kernel/QEMU/libvirt/virtmanager install and patching script for Ubuntu
- String patching script for centos
- Compiling QEMU and libvirtd from source to be more sneaky when doing malware analysis looks like this is the same guy whos script I adapted for string patches.