QTrace is a "zero knowledge" system call tracer, based on QEMU. Its main characteristic is that system call arguments are dumped without the need to instruct the tracer about their structure.
As an example, QTrace can be used to easily dump
win32k.sys graphical system
calls (as well as undocumented ones) despite the intricacies in their arguments
(and the lack of official documentation).
Additionally, QTrace includes a dynamic taint-tracking module, used to (dynamically) track dependencies between system calls (e.g., one of the output arguments of system call A is eventually used as an input argument for system call B).
Traced system calls are serialized to a Protocol Buffer stream and can then be parsed off-line. QTrace includes some basic Python post-processing tools.
The whole infrastructure is mainly targeted to Windows systems, but can be extended to support other OSes as well.
QTrace is still under development, so get ready to find lots of bugs :-)
To compile QTrace just use the following commands:
If you get any error about the need to run
make distclean under the
directory, just run
make another time.
To avoid too many compile-time dependencies, the
compiles QEMU with VNC support only (i.e., no SDL support). Thus, after
QEMU/QTrace is executed, you need a VNC client to connect to the guest.
Remember to also add the
qtrace directory to your library path, as QEMU main
executable must be able to load
QTrace verbosity level can be adjusted by changing the
Finally, if you plan to use the Python tools (under
tools/), you should also compile the Python version of the protobuf module, using the following commands:
cd tools/trace protoc --python_out=. syscall.proto
QTrace adds the following command-line options to QEMU:
qtrace-trace-disabledStart emulation with syscall tracing disabled.
qtrace-taint-disabledStart emulation with taint-tracking disabled.
qtrace-log FILELog QTrace messages to
qtrace-profile PROFILESelect which guest OS profile to use.
qtrace-trace FILESerialize syscalls to
qtrace-syscalls FILTERComma-separated list of syscall names to process.
qtrace-process NAMETrace only guest process with name
qtrace-foreignEnable foreign pointers tracking.
Additionally, QTrace provides some QEMU monitor commands that can be used to enable/disable syscall tracing and taint-tracking at run-time.
The following command line starts a Windows 7 SP0 image with syscall tracing and taint-tracking enabled since the very beginning (slow!).
./i386-softmmu/qemu-system-i386 -qtrace-profile win7sp0 -snapshot -hda win7.qcow2 -qtrace-trace /tmp/win7.trace -qtrace-log /tmp/qtrace.log
The system call trace will be saved to local file
/tmp/win7.trace, while log
messages are directed to
The trace file can then be processed using
tools/qtrace.py. As an example, to
generate a HTML trace of recorded system calls, use the following syntax:
python tools/qtrace.py -o /tmp/win7.html -s src/qtrace/trace/win7sp0_syscalls.h
-s argument is necessary to provide QTrace with the names of the system
calls for the target OS version.
Modifications to QEMU source code
QTrace is currently based on QEMU 1.6.0 but should be quite easy to port it to future QEMU versions.
Most of QTrace code is under the
qtrace/ directory. Modifications to the
original QEMU source code are enclosed within
<qtrace>...</qtrace> tags or
#ifdef CONFIG_QTRACE_* ... #endif directives.
QTrace includes two modules: a system call tracer and a taint-tracking
engine. Most of the code for these modules can be found under the
qtrace/taint directories, respectively.
To separate module-dependent code from QTrace core functionalities, specific preprocessor identifiers have been used:
CONFIG_QTRACE_SYSCALL: Code specific to the system call tracer.
CONFIG_QTRACE_TAINT: Code specific to the taint-tracking engine.
CONFIG_QTRACE_CORE: "Core" QTrace code, not specific to any module.
Briefly, most of QTrace code has been compiled into a a C++ shared library
libqtrace.so), while trying to minimize modifications to original QEMU
The only components left in C are those that act as a bridge between QEMU and
libqtrace.so. The rationale was to keep the C bridge as thin as possible, and
to move most of the functionalities to the C++ library.