Post

Deep Diving into Nyx Part I - The Setup

The Setup

Clone & Compare

I figured the best way to learn what modification that the Nyx has made on top of QEMU is to cloning both repos and compare all files that has been modified/added/deleted. To do so, I used a visual studio code extension Diff Folders (Extension ID: L13RARY.l13-diff)

NOTE: The Nyx QEMU is based off of QEMU 4.2.0, which you can find the in branch named stable-4.2 Here is the command line used to clone the repo git clone -b stable-4.2 https://github.com/qemu/qemu.git for QEMU git clone https://github.com/nyx-fuzz/QEMU-Nyx.git for QEMU-Nyx

After that, should be easy to compare all the files that Nyx has added or modified, for example Capstonev4, Nyx folders appear as added folders

Where Can I Start?

Well, following my Debugging kAFL series, you know we have a example that we can debug and now it’s just a matter of stepping through the source code and learn some more about QEMU and Nyx (two bird with one stone).

This time, I will not use GDB to debug but rather I will use VSCode to play on easy mode… The setup is quite simple, compile the QEMU-Nyx with

1
2
┌[kiwish-4.2]-(Downloads/QEMU-Nyx)-[git:qemu-nyx-4.2.0*]-
└> ./compile_qemu_nyx.sh debug_static

Adding a configuration file into VS Code is simple enough, ask ChatGPT to convert out previous GDB command line to VS Code configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
    "version": "0.2",
    "configurations": [
        {
            "name": "QEMU Debugging",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/x86_64-softmmu/qemu-system-x86_64",
            "args": [
                "-enable-kvm",
                "-machine", "kAFL64-v1",
                "-cpu", "kAFL64-Hypervisor-v1,+vmx",
                "-no-reboot",
                "-net", "none",
                "-display", "none",
                "-chardev", "socket,server,id=nyx_socket,path=/tmp/kafl_kiwi/interface_0",
                "-device", "nyx,chardev=nyx_socket,workdir=/tmp/kafl_kiwi,worker_id=0,bitmap_size=65536,input_buffer_size=131072",
                "-device", "isa-serial,chardev=kafl_serial",
                "-chardev", "file,id=kafl_serial,mux=on,path=/tmp/kafl_kiwi/serial_00.log",
                "-m", "4096",
                "-drive", "file=/home/kiwi/.local/share/libvirt/images/windows_x86_64_vagrant-kafl-windows.img",
                "-fast_vm_reload", "path=/tmp/kafl_kiwi/snapshot/,load=off",
                "-device", "vmcoreinfo",
                "--monitor", "unix:qemu-monitor-socket,server,nowait"
            ],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "/usr/bin/gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        }
    ]
}

Okay, Client

We can now run the QEMU-Nyx by starting the debug session, and set a break point at main() in vl.c In VSCode debug mode and we will now get all the symbol information and the ability to inspect variables within VS Code. Shoutout to Microsoft VSCode dev team!

Well, we got our QEMU-Nyx running, but it’s still waiting on a actual client to supply the corpus and instruct the QEMU-Nye instance what to do.

We will again use kAFL as our “QEMU-Nyx client” to initiate all workflow for us so we can focus on debugging the QEMU-Nyx. If you don’t know how to do that yet, please check the blogpost linked above.

NOTE: When you try to inspect Global variables , you will need to add them to the Watch tab. Ex. global_state variable, right click on the variable and Add to Watch.

NOTE: I had this trouble when I was inspecting the global_state global variable, but however, VS Code mapped the variable to another struct that’s in the original QEMU source code and I had to rename the Nyx’s global_state variable to something else to avoid name collision

Putting Everything Together

  1. Start the kAFL Fuzzer frontend
  2. Start the QEMU-Nyx
  3. Continue the execution of QEMU-Nyx and check the workdirto see if the interface_X socket is there. This is needed by kAFL to initialize the client handshake.
  4. Set desired breakpoints in QEMU-Nyx and continue kAFL execution. Ex. I set a breakpoint at nyx_interface device_realize function
  5. Have fun learning about QEMU and Nyx
This post is licensed under CC BY 4.0 by the author.