QEMU escape: Part 1 Environment Set-up



As a totally newbie in virtualization technology, this post will gives more details in setting up the testing environment for QEMU based on [1].

Environment Setup

In my tesing environment, my host OS is Ubuntu 17.10 and guest OS is Ubuntu 16.04.
Build QEMU
Use the following code to get the desired version of QEMU

$ git clone git://git.qemu-project.org/qemu.git
$ cd qemu
$ git checkout bd80b59
$ mkdir -p bin/debug/native
$ cd bin/debug/native
$ ../../../configure --target-list=x86_64-softmmu --enable-debug \
$                    --disable-werror
$ make -j 4

Before configuring the building environment, follow the steps in [2] to install all necessary libraries. At the same time, make sure the patch files are not merged into the source code.

Create Bootable Drive

Since [1] has skipped this part, so I list the steps here.

qemu-img create -f qcow2 ubuntu.img 60G
qemu-system-x86_64 -enable-kvm -boot d \
-cdrom /path/to/ubuntu-16.04.3-desktop-amd64.iso -m 1024 \
-hda /path/to/ubuntu.img

Then install the Ubuntu in QEMU like virtualbox.

Testing QEMU

Run the following command to boot the virtual machine.

/path/to/qemu-system-x86_64 -enable-kvm -m 2048 -drive \

To test the mapping translation from guest virtual address to host virtual address.
We first compile the following file in guest machine.

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <inttypes.h>

#define PAGE_SHIFT  12
#define PAGE_SIZE   (1 << PAGE_SHIFT)
#define PFN_PRESENT (1ull << 63)
#define PFN_PFN     ((1ull << 55) - 1)

int fd;

uint32_t page_offset(uint32_t addr)
    return addr & ((1 << PAGE_SHIFT) - 1);

uint64_t gva_to_gfn(void *addr)
	uint64_t pme, gfn;
	size_t offset;
	offset = ((uintptr_t)addr >> 9) & ~7;
	lseek(fd, offset, SEEK_SET);
	read(fd, &pme, 8);
	if (!(pme & PFN_PRESENT))
		return -1;
	gfn = pme & PFN_PFN;
	return gfn;

uint64_t gva_to_gpa(void *addr)
	uint64_t gfn = gva_to_gfn(addr);
	assert(gfn != -1);
	return (gfn << PAGE_SHIFT) | page_offset((uint64_t)addr);

int main()
	uint8_t *ptr;
	uint64_t ptr_mem;

	fd = open("/proc/self/pagemap", O_RDONLY);
	if (fd < 0) {

	ptr = malloc(256);
	strcpy(ptr, "Where am I?");
	printf("%s\n", ptr);
	ptr_mem = gva_to_gpa(ptr);
	printf("Your physical address is at 0x%"PRIx64"\n", ptr_mem);

	return 0;

In QEMU, the physical memory of guest machine is a mapped region in Host virtual address space. The code above translates a virtual address in guest machine to a physical address in guest machine. For more details about page map translation please refer to [3].
Then we can use the resolved physical address as offset into the mapped region of virtual address in host machine to locate the address of the string.
The result is given below:

The physical address of the string in guest machine is 0x47c00010. Then we attach gdb on host machine to the qemu-system-x86_64 process, dump the process mapping, locate the address of mapped region and view the string at given address.


As a first step, I give detailed steps for setting up the test environment for qemu escape. But running a Ubuntu desktop in QEMU seems quite slow and unnecessary. Later, I may try find alternative ways to run qemu under nographic mode.


[1] http://www.phrack.org/papers/vm-escape-qemu-case-study.html
[2] https://wiki.qemu.org/Hosts/Linux
[3] https://www.kernel.org/doc/gorman/html/understand/understand006.html
[4] https://github.com/qemu/qemu/commit/39b8e7dcaf04cbdb926b478f825b160d852752b5
[5] https://github.com/qemu/qemu/commit/837f21aacf5a714c23ddaadbbc5212f9b661e3f7

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s