In this article we are going to play with a DLL injection tool on a Windows system that is running on top the Cyberus Virtualization Platform. Using the Tycho Python API, we will see how dead simple it is to check if a process has been subject to DLL injection.


First, we need the typical setup of an analysis box running Windows on top of our supernova hypervisor, and a developer laptop that runs tycho-server.

If you are not familiar with this setup, please have a look into the article Fun with Python and Tycho where this is explained.

Analysis box

To perform the experiment, we first need to put two prerequisites on the analysis box:

Please note that we do not need any other developer tools, debuggers, or anything else apart from this list. The system can be a completely untouched fresh Windows installation.

In practice we can use any DLL injection tool or method, as well as any DLL. The typical bad hacker would use some DLL injection code in the malware that he aims to deploy and the DLL would of course contain malicious content.

I chose this tool and DLL for this article because they can be freely downloaded and serve the purpose of demonstration very well.

Injecting a DLL and Detecting it with Tycho

The first step is to launch the process on the analysis box that is going to be subject of DLL injection. Let’s just fire up calc.exe for that purpose. It could otherwise be any other application, of course.

Next, we switch to the developer laptop and launch a python shell. Whenever we analyse what’s happening in a process via Tycho, we have to connect to the tycho service first and then open the desired process:

>>> from pyTycho import tycho
>>> service = tycho()
>>> calc = service.open_process("calc.exe")

calc is our process handle and is all we need to query information about the running calc.exe instance. Now we can immediately save the list of DLLs that are loaded into this process in a variable by accessing its VAD tree and extracting all the DLL names.

>>> dlls_before = [v.filename for v in calc.get_vad_list() if v.filename.endswith(".dll")]
>>> dlls_before
['\\Windows\\System32\\oleaccrc.dll', '\\Windows\\System32\\user32.dll', '\\Windows\\System32\\kernel32.dll', '\\Windows\\System32\\ntdll.dll', '\\Windows\\winsxs\\\\GdiPlus.dll', '\\Windows\\System32\\oleacc.dll', '\\Windows\\System32\\winmm.dll', '\\Windows\\System32\\WindowsCodecs.dll', '\\Windows\\System32\\dwmapi.dll', '\\Windows\\System32\\uxtheme.dll', '\\Windows\\winsxs\\\\comctl32.dll', '\\Windows\\System32\\version.dll', '\\Windows\\System32\\cryptbase.dll', '\\Windows\\System32\\KernelBase.dll', '\\Windows\\System32\\advapi32.dll', '\\Windows\\System32\\sechost.dll', '\\Windows\\System32\\imm32.dll', '\\Windows\\System32\\msctf.dll', '\\Windows\\System32\\lpk.dll', '\\Windows\\System32\\msvcrt.dll', '\\Windows\\System32\\usp10.dll', '\\Windows\\System32\\gdi32.dll', '\\Windows\\System32\\oleaut32.dll', '\\Windows\\System32\\shlwapi.dll', '\\Windows\\System32\\clbcatq.dll', '\\Windows\\System32\\shell32.dll', '\\Windows\\System32\\ole32.dll', '\\Windows\\System32\\rpcrt4.dll', '\\Windows\\System32\\apisetschema.dll']

That is a lot of DLLs, but nothing special or suspicious yet.

Let us now start RemoteDLL on the analysis box and select our calc.exe process and the Suspender DLL in the user interface. After clicking the “Inject DLL” button, we can see all kinds of success messages in RemoteDLL’s log output:

Now we have 60 seconds until calc.exe freezes. That is enough time to check out if we can detect the DLL injection that we just performed.

Back on the developer laptop’s python shell we can again query the list of DLLs and save them into another variable:

>>> dlls_after = [v.filename for v in calc.get_vad_list() if v.filename.endswith(".dll")]
>>> dlls_after
['\\Windows\\System32\\oleaccrc.dll', '\\Windows\\System32\\user32.dll', '\\Windows\\System32\\kernel32.dll', '\\Windows\\System32\\ntdll.dll', '\\Windows\\winsxs\\\\GdiPlus.dll', '\\Users\\demo3\\Documents\\Suspender.dll', '\\Windows\\System32\\oleacc.dll', '\\Windows\\System32\\winmm.dll', '\\Windows\\System32\\WindowsCodecs.dll', '\\Windows\\System32\\dwmapi.dll', '\\Windows\\System32\\uxtheme.dll', '\\Windows\\winsxs\\\\comctl32.dll', '\\Windows\\System32\\version.dll', '\\Windows\\System32\\cryptbase.dll', '\\Windows\\System32\\KernelBase.dll', '\\Windows\\System32\\advapi32.dll', '\\Windows\\System32\\sechost.dll', '\\Windows\\System32\\imm32.dll', '\\Windows\\System32\\msctf.dll', '\\Windows\\System32\\lpk.dll', '\\Windows\\System32\\msvcrt.dll', '\\Windows\\System32\\usp10.dll', '\\Windows\\System32\\gdi32.dll', '\\Windows\\System32\\oleaut32.dll', '\\Windows\\System32\\shlwapi.dll', '\\Windows\\System32\\clbcatq.dll', '\\Windows\\System32\\shell32.dll', '\\Windows\\System32\\ole32.dll', '\\Windows\\System32\\rpcrt4.dll', '\\Windows\\System32\\apisetschema.dll']

This list of DLLs looks very similar, but with a sharp eye we can see that it contains one new item that was not there on the first query.

But let’s not strain our eyes when we can just let python determine the difference between both lists:

>>> set(dlls_after) - set(dlls_before)

That’s our Suspender DLL!

One detail is that we just sticked to file entries in the VAD tree that have a .dll ending in their filename. A full-blown solution would be a bit more exact, but we kept it simple for the sake of this demonstration.

What Next

Starting with these few example lines it would be simple to write a little watcher script that periodically checks a set of processes for changing DLL lists. For every program that is not usually known to load DLLs at late runtime, it is of course immediately suspicious if some new DLL pops up.

A possibly nice idea would be to glue such a script together with some database that maintains lists of legitimately loaded DLLs for different applications.

Instead of polling for such events periodically, the script could also install breakpoints that stop the apps that are watched whenever they are rescheduled, or at specific systemcalls. The Tycho Python API provides many other possibilities.

Another idea that might have potential is to put memory-write breakpoints on the VAD tree items in order to detect if their structure or content is changed. But that is out of the scope of this article.


Leave a Reply

Your email address will not be published. Required fields are marked *