Detecting bochs from your OS?
Detecting bochs from your OS?
How do you detect your OS is running inside bochs?
- Brynet-Inc
- Member
- Posts: 2426
- Joined: Tue Oct 17, 2006 9:29 pm
- Libera.chat IRC: brynet
- Location: Canada
- Contact:
This is a tricky question, there really should be a nice "standard" way to detect if an OS is being virtualized.. but most of the time you have to rely on a flaw in the VM, something that clearly isn't very reliable though..
Here is an interesting example I found.. http://invisiblethings.org/papers/redpill.html
Although this code has no effect in QEMU running OpenBSD - I have no way to test the validity of the code..
Here is an interesting example I found.. http://invisiblethings.org/papers/redpill.html
Although this code has no effect in QEMU running OpenBSD - I have no way to test the validity of the code..
There also some code in these posts
http://www.osdev.org/phpBB2/viewtopic.p ... t+emulator
http://www.osdev.org/phpBB2/viewtopic.p ... t+emulator
Re: Detecting bochs from your OS?
Hi,
This means you need to rely on flaws in the virtual machine, but you need to be a little tricky - for open source emulators like Bochs you want to rely on flaws that can't be easily changed. For an example, when Bochs was emulating an 80486 the CPUID instruction would say the CPU is an 80486DX but the 80486DX didn't actually support the CPUID instruction, so I used this as part of my Bochs detection code. Later, I rewrote "cpu/cpuid.cc" and fixed this problem (and others), which broke my own Bochs detection code.
For Bochs, first I try a little pre-check to see if it was compiled with the 0xE9 hack:
This isn't a reliable test (it's easy to compile Bochs without the 0xE9 hack), but it can save time.
Next, RDTSC counts instructions (not cycles) and Bochs doesn't emulate caches. I flush caches (WBINVD) and then use instructions like "MUL dword [0x00000FFE]" (which is deliberately misaligned and should cause 2 cache misses). RDTSC will count instructions, so one WBINVD and five MULs will be 6 "cycles".
This doesn't work if RDTSC isn't supported (if Bochs is emulating an 80486). In this case I do 2 loops, where both loops run from one PIT IRQ to the next (a fixed amount of time). For the first loop I repeatedly flush caches (WBINVD) and do several misaligned reads (e.g. "cmp dword [0x00006FFF],0"), and for the second loop I repeatedly do NOP and several misaligned reads. Then I compare how many times each loop executed. For Bochs the difference is small and sometimes the first loop does more iterations (flushing the caches is faster than NOP). For this I'd recommend making sure paging isn't enabled, as Bochs does emulate TLBs and flushes the TLBs when you do WBINVD (which is wrong - WBINVD should only flush instruction and data caches, not the TLBs). With paging enabled the first loop would be slower due to TLB flushing, which makes it hard to detect Bochs using this method.
The problem is that it's hard to write code that doesn't also detect other emulators. With my method, you can't tell the difference between Bochs and VirtualBox (they have the same flaws).
I've also got code for detecting Qemu, VMware and VirtualPC. Qemu doesn't emulate caches, RDTSC is always supported and RDTSC measures cycles and not instructions. VMware has a special I/O port that will change some registers if you touch the IO port when EAX is set to a special magic number, which can be used to find out which version of VMware is running. VirtualPC has a special instruction (which should be an invalid opcode) - you just execute this instruction and see if you get an exception or not.
Anyway, the latest version of my code isn't on my web site yet, so I attached it. It's still a work in progress though - I'm still looking for more information on detecting other virtual machines.
Cheers,
Brendan
Unfortunately, Brynet-Inc is right - there should be a standard way of detecting virtual machines but there isn't. I personally blame security "experts", who want virtual machines to be entirely undetectable so they feel good about using them for honey pots (which is stupid if your code must be running at CPL=0 to detect the virtual machine).Candy wrote:How do you detect your OS is running inside bochs?
This means you need to rely on flaws in the virtual machine, but you need to be a little tricky - for open source emulators like Bochs you want to rely on flaws that can't be easily changed. For an example, when Bochs was emulating an 80486 the CPUID instruction would say the CPU is an 80486DX but the 80486DX didn't actually support the CPUID instruction, so I used this as part of my Bochs detection code. Later, I rewrote "cpu/cpuid.cc" and fixed this problem (and others), which broke my own Bochs detection code.
For Bochs, first I try a little pre-check to see if it was compiled with the 0xE9 hack:
Code: Select all
in al,0xE9 ;Get return value from Bochs debug port
cmp al,0xE9 ;Is Bochs running (and compiled with "./configure --enable-port-e9-hack")?
je .isBochs ; yes, running in Bochs
Next, RDTSC counts instructions (not cycles) and Bochs doesn't emulate caches. I flush caches (WBINVD) and then use instructions like "MUL dword [0x00000FFE]" (which is deliberately misaligned and should cause 2 cache misses). RDTSC will count instructions, so one WBINVD and five MULs will be 6 "cycles".
This doesn't work if RDTSC isn't supported (if Bochs is emulating an 80486). In this case I do 2 loops, where both loops run from one PIT IRQ to the next (a fixed amount of time). For the first loop I repeatedly flush caches (WBINVD) and do several misaligned reads (e.g. "cmp dword [0x00006FFF],0"), and for the second loop I repeatedly do NOP and several misaligned reads. Then I compare how many times each loop executed. For Bochs the difference is small and sometimes the first loop does more iterations (flushing the caches is faster than NOP). For this I'd recommend making sure paging isn't enabled, as Bochs does emulate TLBs and flushes the TLBs when you do WBINVD (which is wrong - WBINVD should only flush instruction and data caches, not the TLBs). With paging enabled the first loop would be slower due to TLB flushing, which makes it hard to detect Bochs using this method.
The problem is that it's hard to write code that doesn't also detect other emulators. With my method, you can't tell the difference between Bochs and VirtualBox (they have the same flaws).
I've also got code for detecting Qemu, VMware and VirtualPC. Qemu doesn't emulate caches, RDTSC is always supported and RDTSC measures cycles and not instructions. VMware has a special I/O port that will change some registers if you touch the IO port when EAX is set to a special magic number, which can be used to find out which version of VMware is running. VirtualPC has a special instruction (which should be an invalid opcode) - you just execute this instruction and see if you get an exception or not.
Anyway, the latest version of my code isn't on my web site yet, so I attached it. It's still a work in progress though - I'm still looking for more information on detecting other virtual machines.
Cheers,
Brendan
- Attachments
-
- detectvm.asm
- VM detection code
- (11.02 KiB) Downloaded 121 times
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
- Brynet-Inc
- Member
- Posts: 2426
- Joined: Tue Oct 17, 2006 9:29 pm
- Libera.chat IRC: brynet
- Location: Canada
- Contact:
I hear VirtualBox's emulated video card uses a bogus PCI vendor/product ID, but most would try to emulate "commonly" supported chipsets, The reason for this is to support multiple "guest operating systems" without custom drivers.prashant wrote:Can we check for the PCI device IDs of different emulators? Haven't checked if they are unique though.
It wouldn't make sense for VM's to have unique PCI ID's if there trying to support a wide range of OS's..
One thing I noticed is the "ATA" vendor/model name of most Emulators is unique though, Perhaps that could be used.. although it would be sort of hack-ish. (And you're able to change the default name in a few emulators..)