This article demonstrates how simple it is to setup our analysis tool Tycho and plays with the Tycho Python API in order to outline its potential. We will pause and resume processes, read interesting process information, and inject errors using the Tycho Python API.
Tycho, which is the name of our live binary analysis tool (you may also regard it as a super debugger), can be used to hook into processes in order to analyze/debug them. As user frontends it may talk with GDB, IDA Pro, or any graphical debugger application that supports GDB, which feels familiar to most users.
In this post, we will not regard the GDB interface, but the Python API. We will see that it is really easy to integrate Tycho into your own python scripts and this way combine it with whatever other libraries you have been using already (like e.g. Volatility).
The Python library part is open source and you can always get the latest version in our Github Repository.
In order to analyse processes with Tycho via Python, we first need to set up both the analyst system and the system that is subject to analysis. This setup consists of just 2 steps:
supernovaon the analysis box
tycho-serveron the developer laptop.
The following picture shows the typical setup:
- Let’s call the box on the left the analysis box. It hosts a completely unmodified Windows 7 box. We activate network boot in order to boot our
supernovahypervisor on it, which will then in turn boot the already installed Windows.
- The laptop on the right is the analyst- or developer laptop. It will communicate with our hypervisor and remote control the debugging/analysis that will happen to the processes that run on the box at the left side.
When the analysis box gets to boot the
supernova hypervisor, the hypervisor in turn will chainload the operating system that is already installed. This way
supernova can quickly be deployed to any system with a reboot. After another reboot, it’s gone again.
Now we need to start
tycho-server on the developer laptop.
tycho-server connects to the running
supernova instance via serial cable or USB debug cable and listens on a TCP port on the developer laptop. This way we get a communication channel to the hypervisor and can use python scripts that instruct it to do what we need.
Now that we have a running hypervisor that we can talk to, let’s fire up a python shell and stop the builtin calculator
from pyTycho import tycho = tycho() service = service.open_process("calc.exe") calc calc.pause()
supernova is kind of “armed” to stop
calc.exe as soon as it sees this process being scheduled again. When this happens, we observe the following:
An interesting detail is that this happens completely without support from the Windows side. Windows is not aware of us pausing this process! With a closer look at the task manager we see that
calc.exe burns 50% CPU cycles, which is a side effect of our process pausing method. Note that this does not really burn 50% of the CPU cycles.
calc.resume(), we can resume normal process execution and everything is like it was before.
We can also do more. Let’s print the PID of
calc.exe and see how many threads it has.
>>> calc.get_pid() 2932L >>> calc.get_thread_list() 188L][
As we can see, our running
calc.exe instance has PID
2932. Task manager shows us the same number. The
get_thread_list() function yields us a list with only a single item. If we do the same query on the also running Internet Explorer, we get a more interesting result as it has a few threads running:
>>> iexplore = s.open_process("iexplore.exe") >>> iexplore.get_thread_list() 4004L, 3112L, 2364L, 2652L, 1208L, 2624L, 2948L, 2692L, 1372L, 2876L, 1228L][
Let’s see what else we can do. How about listing what DLLs are loaded into a process? This information is listed in the VAD tree in the Windows kernel:
>>> [n.filename for n in calc.get_vad_list() if n.filename.endswith(".dll")] '\\Windows\\System32\\oleaccrc.dll', ['\\Windows\\System32\\user32.dll', '\\Windows\\System32\\kernel32.dll', '\\Windows\\System32\\ntdll.dll', '\\Windows\\winsxs\\amd64_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.7601.17514_none_2b24536c71ed437a\\GdiPlus.dll', '\\Windows\\System32\\oleacc.dll', '\\Windows\\System32\\winmm.dll', '\\Windows\\System32\\WindowsCodecs.dll', '\\Windows\\System32\\dwmapi.dll', '\\Windows\\System32\\uxtheme.dll', '\\Windows\\winsxs\\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_fa396087175ac9ac\\comctl32.dll', '\\Windows\\System32\\version.dll', '\\Windows\\System32\\cryptbase.dll', '\\Windows\\System32\\rpcrt4.dll', ...]
We can also kill
calc.exe by sending it a page fault:
>>> calc.pause() >>> calc.inject_pagefault(0, 5) True >>> calc.resume()
inject_pagefault line we inject a page fault at address
0, which looks like a null pointer dereference. From the perspective of the Windows kernel, this page fault came directly from the CPU. In reaction to that, it kills the calculator process.
We have seen how easy it is to prepare the analysis box for tampering around with it using the Tycho Python API. After rebooting the analysis box, the system is completely restored to the untouched state it was in before we booted
We have seen how to pause and resume processes like it is possible with normal debuggers - but without the support of the Windows kernel. This way the applications that run on this system cannot see any debugger artifacts.
In addition to that, we listed various process information (PID, thread list, VAD tree) and also killed a process by sending it a page fault.
Generally, there is more functionality like the following:
- Stop and resume a process or individual threads
- Read arbitraty memory from the process’ address space
- Manipulate the process’ memory
- Read out the whole VAD tree,
PEBinformation of a process from the Windows kernel space
- Set breakpoints on…
- specific instructions
- System calls (without library hooking)
- The number of features is steadily growing, so stay tuned, please.
We will showcase more features within the next blog articles.