DLL Hijacking for Persistence - SteelSeries Engine

About The Project

With the pandemic in full swing and work from home being normal it’s natural to upgrade your home setup to make work as enjoyable as possible. Maybe you don’t have those nice monitors at home that you do have at work, but hey at least you bought a new mouse and no longer have to use the track pack! This is where the project comes into play.

As a casual gamer, having a “gaming mouse” that I can blame for why I keep dying in CS:GO, but also use during the workday is ideal. The interesting thing about some brands of gaming mice is the centralized hub that some have to enable multiple profiles and various macros. This blog post covers playing around with one manufacturer in particular SteelSeries and some fun things found along the way.

Steel Series Engine

SteelSeries, a manufacturer of gaming hardware has an application (SteelSeriesEngine) that allows for the LEDs on your gaming hardware to represent various in-game information. For example, low on ammo? Go ahead and flash red. This application by default is scheduled to start on boot but only runs with an integrity level of medium.


Right off the bat, there doesn’t appear to be any obvious privilege escalation potential. However, having the SteelSeries Engine start on boot gives us the potential for a persistence mechanism.

Notes on DLLs and DLL Loading within Windows

DLLs have an explicit hierarchy of locations that are searched before anything getting loaded. Referencing Microsoft’s documentation here, we can see that the default search order is as follows:

  1. The directory from which the application loaded.
  2. The system directory.
  3. The 16-bit system directory.
  4. The Windows directory.
  5. The current directory.
  6. The directories that are listed in the PATH environment variable.

The listing above assumes that SafeDLLSearchMode is enabled. If disabled, the search order is slightly modified to the order below:

  1. The directory from which the application loaded.
  2. The current directory.
  3. The system directory.
  4. The 16-bit system directory.
  5. The Windows directory.
  6. The directories that are listed in the PATH environment variable.

Certain APIs will let you over ride these searching paths all together and specificy a directory of the developer’s chosing.

Popping open Procmon, we can see if there are any DLLs that are attempted to be loaded but fail. The image below shows Procmon output containing DLLs that were not found when the application started.


A couple of critical things to note here, elevated privileges are required in order to modify files within C:\Progrm Files\SteelSeries\SteelSeries Engine 3\. Additionally, the DLLs listed here are actual Microsoft DLLs therefore we’re going to really stand out if our dropped DLL is not signed by Microsoft. However, this is a blog about experimentation in both a blue/red team context, so we’ll go further.

Taking a deeper with loaded modules via ProcExplorer, profapi.dll doesn’t appear to be actively loaded. That’s not to say it may not be loaded later, or if there’s some functionality that would then trigger the load and execution. For this demo, profapi.dll will be used as the target application.


Building a DLL for Testing

Before building the DLL, identify whether the target application is 32 or 64 bit.


Visual Studio Community Edition has a template for DLLs and can be used to quickly prototype a PoC. The template below has specific cases for handling when the process is attached, detached to a running process or when a thread begins or ends execution. You can get really creative with how you want your payload to run here. However, we’ll call good ol’ deprecated WinExec to simply spawn notepad.exe. The first argument is the program to launch and the 2nd parameter indicated whether or not to show the window.


After compiling the application and placing it within C:\Progrm Files\SteelSeries\SteelSeries Engine 3\ and rebooting the machine, ProcessExplorer shows a notepad.exe child process.


As previously stated, our crafted profapi.dll is not signed by Microsoft, and has no description. A quick google of said DLL will lead you to see it’s typical location is wthin C:\Windows\System32. This mechanism is by no means stealthy, but it’ll be loaded on reboot providing a nifty persistence mechanism.

Beyond The Blog

If you’re looking to find your own opportunities for DLL hijacking, I’ve linked to some blog posts below that provide further in-depth resources into the hunting process. Thank you for reading!

Other DLL Hijacking Resources