Exploring an Assembly Loading Technique and Detection Mechanism for the GfxDownloadWrapper.exe LOLBIN

Original text by BOHOPS


LOLBINs (Living-of-the-Land Binaries) have been a hot topic these last few years in the security industry as it seems there is a new one released almost weekly. Many of these LOLBINs are documented at the LOLBAS Project which describes the respective (alternate) functionality, use cases, and baseline detection information.

For the most part, LOLBINs featured in the LOLBAS project are Windows signed binaries. These typically include binaries that are a part of the operating system (Windows Signed) and other functional binaries that are added to the operating system later (Microsoft signed). However, there is another class of LOLBINs that are provided by third party vendors and are actually signed by Microsoft as well. In this blog, we will:

  1. Take a closer look at GfxDownloadWrapper.exe, a third party LOLBIN, and discuss a new execution technique that could be used for defense evasion.
  2. Take a look at the loading mechanism in GfxDownloadWrapper.exe and see if we can build a (generic) detection capability to identify the behavior within this utility as well as other, similar LOLBINs.

Introducing GfxDownloadWrapper

GfxDownloadWrapper.exe is a binary that is included with Intel video card driver software. It is a .NET application that supports the Intel Graphics Control Panel and game graphic settings. A quick analysis of the Authenticode signature shows that GfxDownloadWrapper.exe is catalog signed by the “Microsoft Windows Third Party Component CA 2012” issuer:

On one of my test workstations, there are over 20 instances of GfxDownloadWrapper on the file system located in subdirectories under c:\ProgramData\Package Cache\ and the c:\Windows\System32\DriverStore\FileRepository\. This is likely because of updates to driver and re-installation of the driver over the last few years.

As a component of a popular driver software and having Microsoft’s genuine seal of approval, let’s further explore GfxDownloadWrapper as a vector for potential misuse…

GfxDownloadWrapper Download Functionality

In February 2019, @egre55 tweeted about an interesting download capability for GfxDownloadWrapper.exe, which was eventually added to LOLBAS:

However, this download functionality did not properly work with my first test attempt:

Since this is a .NET application and we have access to 20 or so versions of the relatively small program, we can quickly ‘decompile’ old and new version of GfxDownloadWrapper then take a peek at the source code with dnSpy. In this case, version and were quickly analyzed and diffed to show the following changes:

Interestingly, it appears the vendor decided to patch the program and implement restrictions to prevent arbitrary downloads of various and sundry content. Certainly a good thing, but with a cache of previous versions available at our disposal, we can simply identify a version without the restrictions and leverage accordingly with success:

Now, let’s shift gears and explore an interesting code execution technique…

GfxDownloadWrapper Assembly DLL Abuse

Analyzing the Source Code

With the source code available to us, we continue to explore GfxDownloadWrapper.exe and see some very interesting code at the Main() entry point:

Interestingly, GfxDownloadWrapper.exe appears to load an assembly from disk , and it looks like we have an opportunity to influence what is loaded with some input argument manipulation. As we explore further, we can infer that our initial theory is (likely) true since the program calls the internal InvokeDll() method to process an assembly with methods named ApplyRecommendedSettings(), RestoreRecommendedSettings() or CacheCleanup().

Next, we take a peak at the internal InvokeDLL() method and take a note of a few important assembly class methods and properties that can potential help us achieve our objective of loading an arbitrary managed assembly:

Determining the Inputs

In the Main() method, we capture our initial input requirements. Based on a simple input validation function, the access entry point requires four (4) arguments. The first argument requirement [1]args(0), is to simply the string value of “run”. The second argument requirement [2]args(1), is a string path to our assembly DLL payload. The third argument requirement [3]args(2), is a numeric string value for that maps to one of the required assembly methods. The fourth and final argument requirement [4]args(3), is an interesting string value that expects a semi-colon (;) as a split delimiter for multiple game identifiers with a prefix of an AppData relative path. The input requirements are shown in the following image:

When we put everything together, the following command format should be valid (Note: we’ll test this later):

GfxDownloadWrapper.exe "run" "[path\to\payload.dll]" "Method Number" ";AppData\Local\Intel\Games\[Some random value]"

Building a Proof-of-Concept Payload

As previously determined, we will need to prepare an assembly payload. In our test case, we will build an assembly DLL and use CacheCleanup for the entry method name (so our command method argument value will be “2”). Furthermore, we will need to declare the method as “public” since GfxDownloadWrapper queries for exported types to determine which of those are visible outside of the assembly:

Additionally, our declared method requires a string argument as shown in the Invoke() method:

To keep our source code/payload lean and simple, we’ll invoke Notepad.exe with the following assembly C# code:

Putting It All Together

With our payload compiled and our argument strategy worked out, let’s use the following command to execute the payload:

GfxDownloadWrapper.exe "run" "c:\test\np.dll" "2" ";AppData\Local\Intel\Games\a"

Note: The final character (“a”) in argument 4 was chosen randomly. This suffix value can be another value/string/etc. There may be more interesting ways to handle this argument.

As expected, our payload successfully executes after loading our ‘malicious’ assembly:

Now let’s shift gears and talk about detection…

Detecting .NET Assembly Load Events

Identifying Loaded Assemblies

There are several interesting detection opportunities beyond monitoring/hunting for process creation events and suspicious command line usage (which are still viable, of course). Recalling the static analysis that we conducted earlier, Assembly.LoadFrom() of the System.Reflection namespace, is the method used to read and load the assembly from the assembly module (DLL) into the GfxDownloadWrapper application (App Domain). We can actually see this if we take a peek at the GfxDownloadWrapper process properties with Process Hacker. Under the .NET Assemblies tab, the loaded assembly (ClassLibrary1) and DLL module (np.dll) are shown:

Process Hacker obtains this (meta)data from Event Tracing for Windows (ETW), a facility for “provider-defined data that describes the current state of an application or operation” (Microsoft Docs). ETW providers are “applications that contain event tracing instrumentation”, of which provide events for ETW consumers. Just like Process Hacker consumes ETW data for real-time display, let’s see if we can identify the provider of interesting .NET/CLR (Common Language Runtime) events and build a quick and dirty real-time monitor (“EDR?”) to catch Assembly Load events.

Quick Note on ETW Offensive Tradecraft: If you are familiar with ETW and offensive security trends, you are likely aware of the various and sundry ETW tampering techniques for disrupting ETW event collection and processing for an application. These techniques are effective, but there is still value in leveraging ETW event collection even if such a disruptive technique is deployed. Depending on the technique and usage circumstance(s), critical metadata of an application can still be collected up until the actual disruption event itself, which may be all that is required for detection success. For more information on ETW tampering, take a look at Adam Chester‘s incredible research blog as well as Dom Chell and crew’s fantastic MDSec blog where they cover .NET tradecraft quite extensively.

Investigating a Candidate ETW Provider

With a bit of research and strategic Googling, we identify the The CLR Runtime Provider [GUID e13c0d23-ccbc-4e12-931b-d9cc2eee27e4] as the candidate ETW provider. According to the documentation, this provider should furnish all that is needed to achieve our goal. This notions holds true when Drilling further into the CLR ETW documentation as we find information about Loader ETW events under the LoaderKeyword keyword, which seems to have the event metadata for the events that we would like to observe:


Preparing for the Monitor Coding Project

With our candidate ETW provider in hand, we continue to research further to identify open source and public code samples that will be helpful for building our POC monitoring program. Fortunately for us, Microsoft provides excellent code resources for a variety of use cases, and ours is certainly no exception.

For .NET applications, Microsoft makes available the Trace Event library (Microsoft.Diagnostics.Tracing.TraceEvent) for simplifying the logging of ETW events, which is available via NuGet. For preparing the environment and adding the trace library to our CSharp project, please refer to this helpful post by Alex Khanin.

Furthermore, Microsoft kindly provides code samples on Github for working with the trace library to capturing event data. We will use the 31_KernelAndClrMonitor.cs code sample as the basis of the monitor program:

Coding and Building the Proof-of-Concept Monitor

Within the sample project, we first make a few changes by removing unneeded overhead, timing elements, and kernel references. Second, we convert the Run() method into Main() since it is a console application. Lastly, we edit the heart of the program to ensure that we establish a session to only collect the (Loader) events that are useful for our purposes.

In the subsequent screenshot, the CLR Runtime Provider is enabled by the session.EnableProvider() method and is identified by ClrTraceEventPraser.ProviderGuid. We also specify ClirTraceEventParser.Keywords.Loader for raising events under the LoaderKeyword Keyword.

Note: The proof-of-concept code for our monitor can be found here.

After running our “Assembly Load Monitor” and invoking the GfxDownloadWrapper.exe, we can observe some very interesting information such as:

  • Process CmdLine
  • Assembly Name
  • Assembly Module (DLL)

To take this a step further, we could parse the interesting data and send a message to the Event Viewer or log facility for post-processing. However, we’ll save that along with a few stress test cases for another day. All things considered, ETW is quite powerful and many other useful data sources can be tapped for the greater good!

Other Defensive Considerations

Application Control

This technique did not bypass AppLocker with a default rules policy or Windows Defender Application Control (WDAC) with an enforced code integrity policy. If using an application control solution and customizing rules based on code signing as a trust enforcement mechanism, consider blocking application instances of GfxDownloadWrapper.exe or removing the catalog signature from the Catalog database.

Note: Be very careful if attempting to remove catalog signatures from the catalog database. Unintended issues may arise.

Attack Surface Reduction

Driver Rollback and support software caching are certainly viable use cases for maintaining instances of previous software to address fallback issues. However, vendors (and subsequently organizations due to downstream impact) should consider removing much older-than-necessary versions of unused drivers and software to reduce risks associated with abuse and to promote the viability of applied patches in newer versions of the software. In addition to managing the presence of the software, vendors should consider maintaining catalog hygiene to remove the signatures of older software when new software updates are released.


Thank you for taking the time to read this blog post. If you have any questions or comments, please feel free to reach out on here or on Twitter.

РубрикиБез рубрики

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *