Virtual Machine Introspection for KVM.
This is the userland component named nitro. It will receive the events generated by KVM and display them.
python 3docoptlibvirtioctl-opt Python 3cffi Python3(optional)libvmi(optional)rekall(optional)
- Setup a VM. Make sure to use the
qemu:///systemconnection. Go to thetestsfolder to find a packer template and an import script if you don't have one already.
(Nitro only supports for now Windows XP x64 and Windows 7 x64, see the Note section below)
-
Make sure that you have loaded the modified kvm modules. (
cd kvm-vmi && make modules && make reload) -
Start the VM that you would like to monitor.
-
Wait for the desktop to be available on the VM.
-
Start
Nitrowith./main.py <vm_name>.
"""Nitro. Usage: main.py [options] <vm_name> Options: -h --help Show this screen --nobackend Don't analyze events -o --output Output file (stdout if not specified) """ Nitro monitors the given <vm_name> syscalls by activating a set of traps in KVM. The optional components listed above are needed only if you want to extract more information about the captured events. See the Backend section.
Here i will assume that you have installed only the required ones. Therefore you have to run Nitro with the option --nobackend.
It will run until the user sends a CTRL+C to stop it, in which case Nitro will unset the traps and write the captured events in a file named events.json.
By defaults, Nitro will print events to stdout. If this is not desired --out can be used to redirect output into a file.
An event should look like this output
{ "direction": "enter", "rax": "0x1005", "vcpu": 0, "type": "syscall", "cr3": "0x1b965000" },A successful run should give the following output :
$ ./main.py --nobackend nitro_win7x64 Setting traps to False Finding QEMU pid for domain nitro_win7x64 Detected 1 VCPUs Setting traps to True Start listening on VCPU 0 {'cr3': '0x6cdc000', 'direction': 'exit', 'rax': '0x3f', 'type': 'syscall', 'vcpu': 0} {'cr3': '0x6cdc000', 'direction': 'enter', 'rax': '0x138', 'type': 'syscall', 'vcpu': 0} {'cr3': '0x6cdc000', 'direction': 'exit', 'rax': '0x0', 'type': 'syscall', 'vcpu': 0} {'cr3': '0x6cdc000', 'direction': 'enter', 'rax': '0x58', 'type': 'syscall', 'vcpu': 0} {'cr3': '0x6cdc000', 'direction': 'exit', 'rax': '0x0', 'type': 'syscall', 'vcpu': 0} {'cr3': '0x6cdc000', 'direction': 'enter', 'rax': '0x138', 'type': 'syscall', 'vcpu': 0} {'cr3': '0x6cdc000', 'direction': 'exit', 'rax': '0x0', 'type': 'syscall', 'vcpu': 0} {'cr3': '0x6cdc000', 'direction': 'enter', 'rax': '0x5f', 'type': 'syscall', 'vcpu': 0} Setting traps to False The Backend is supposed to analyze raw nitro events, and extract useful informations, such as:
- process name
- process PID
- syscall name
Rekall is used in symbols.py to extract the syscall table from the memory dump.
Unfortunately, Rekall is not available as a Debian package. For now you will have to install it system-wide with pip. (Python2)
$ sudo pip2 install --upgrade setuptools pip wheel $ sudo pip2 install rekall -
Compile and install
libvmi. See the install notes -
Configure the file
libvmi.conf, which is already provided in the repo
Configure the name of your vm that you want to monitor : (only Windows 7 x64 is supported here)
nitro_win7x64 { ostype = "Windows"; win_tasks = 0x188; win_pdbase = 0x28; win_pid = 0x180; win_pname = 0x2e0; } At least, the following keys are required :
win_taskswin_pdbasewin_pidwin_pname
The python wrapper on top of Libvmi is based on CFFI and needs to be compiled.
$ python3 nitro/build_libvmi.py If you have installed everything correctly, you can run Nitro : ./main.py nitro_win7x64
An event should now look like this:
{ "event": { "cr3": "0xbda6000", "direction": "enter", "type": "syscall", "vcpu": 0, "rax": "0x14" }, "name": "nt!NtQueryValueKey", "process": { "name": "services.exe", "pid": 456 } },