Introducing pywintrace: A Python Wrapper for ETW
Event tracing for Windows (ETW) is a lightweight logging facility first introduced with Windows 2000. Originally intended as a software diagnostic, troubleshooting and performance monitoring tool, it was greatly expanded in Windows Vista to create a lightweight debugging mechanism.
The basic architecture of ETW has three discrete components: providers, controllers, and consumers. The providers supply the trace data, controllers control capture sessions, and the consumers process the data returned from the providers. Figure 1 shows an overview of this architecture.
Windows 7 has more than 600 providers installed by default, many of which provide verbose trace data. ETW data can be used to conduct research into almost any area of the OS without the need for a debugger. A default Windows installation ships with all the tools needed to capture ETW data, but these tools are somewhat inflexible. Another drawback is that a different tool is usually needed when analyzing the captured data.
Prior to making the decision to create an entirely new project, research was conducted to see if there was an existing project that would work. Several projects were found, with KrabsETW from Microsoft and Google’s pyetw looking the most promising. Neither of these were quite right, however, since KrabsETW is not written in Python and therefore not compatible with existing projects, and pyetw is no longer maintained. We found simple programmatic access to ETW using Python was missing.
Pywintrace is a Python package developed by the FireEye Innovation and Custom Engineering (ICE) team to fill the need for a flexible wrapper around Windows APIs to accelerate ETW research. Using Python’s ctypes, the team created a module that can create and control a capture session, as well as process trace events. The package contains three main classes:
- EventProvider – Wraps interactions with ETW providers
- EventConsumer – Consumer to process messages emitted from ETW trace sessions
- ETW – Main class for ETW captures
Using pywintrace is simple, and it can be extended as needed to fit nearly any desired capture scenario. Typically, a user would create an instance of the ETW class to begin capturing data. Figure 2 shows a simple example of this.
In Figure 2, the ETW provider “Some Provider” with GUID “11111111-1111-1111-1111-111111111111” is being captured, and the resultant message data is written to the console. The run function in Figure 2 is a helper function that will process the messages returned by the system. If desired, a user may specify their own callback function and process the messages however they choose.
The example in Figure 2 is simple, but shows how easy pywintrace is to use. For more examples, see the examples directory of the pywintrace package.
Capturing Interesting Data
While there are many interesting providers to investigate, a blog published by Microsoft demonstrated the usefulness of the Microsoft-Windows-WinINet provider on Windows 7. Another interesting WinInet provider, Microsoft-Windows-WinINet-Capture, was added with Windows 10. Using pywintrace the ICE team was easily able to perform an ETW capture using both. Since the ETW messages are delivered chronologically by the system, there is no need for special processing when using multiple providers. Figure 3 shows some of this capture data.
At a minimum, each message contains a message ID, an associated event type name, description, task name, and an EventHeader. In Figure 3 the first message (ID 108), a Microsoft-Windows-WinINet provider message, shows a request handle being created for the server at ‘www.google.com’. Of note is that domain specific information is returned, and is emitted from several other providers as well – without the need for a Layered Service Provider (LSP) or driver.
In the second message (ID 2001), a Microsoft-Windows-WinINet-Capture provider message, shows the request data being sent to the server. The ‘payload’ field of this message is a hex stream of the plaintext traffic. The decoded data is shown in Figure 4.
It should be noted that this capture was performed on a Windows 10 machine using the Edge browser. Other browser and OS combinations may provide different results. This information can be very useful, however, since it could be used to detect malicious activity that would normally be masked by a layer of encryption.
Capturing Malicious Activity
Figure 5 shows a snippet of a WinINet capture of traffic generated by a malware sample in a controlled environment.
Here the malware is seen beaconing out to its command and control (C2) server and requesting a web page. This single message shows the URL of the page being requested as well as the Process ID and Thread ID that originated the malicious activity. From this message, the URL could be used to determine if the request was malicious and the process / thread information could be used to track down the malware – especially in cases of process hollowing or DLL injection.
ETW provides a very powerful lightweight trace mechanism conveniently baked into Windows. Among other things it can be used to potentially detect malicious activity on an endpoint. Using pywintrace to capture ETW data is simpler than using multiple tools to do the same job, and since it is written in Python it is easy to modify for whatever is needed. This makes the job of slogging through the hundreds of ETW providers much easier, and accelerates efforts to find interesting providers.
Download pywintrace today!
Special thanks to the entire ICE team. ICE is a small, highly trained, team of engineers that incubate and deliver capabilities that matter to our products, our clients and our customers. ICE is always looking for exceptional candidates interested in solving challenging problems quickly.
Also, thanks to Microsoft for their extensive blog posts and documentation on ETW.