I’ve released a tool called Sealighter-TI that uses research from Alex Ionescu and James Forshaw, plus code from Clément Labro’s project PPLDump, to get events from the protected Microsoft-Windows-Threat-Intelligence ETW provider without a signed driver to putting Windows into Test Signing mode.

UPDATE (July 2022):

Microsoft patched the exploit used by PPLDump and SealighterTI, so the code will no longer work on up-to-date systems. For a similar solution, see my blog on using Vulnerable Drivers for the same purpose.

Protecting AntiMalware Services (for real this time)

A few months ago I wrote a blog about the Microsoft-Windows-Threat-Intelligence ETW provider, and how only processes started at least as Protected Process Light Anti-Malware (or PPL-AM) can receive events from it. I made a tool called PPLRunner that would allow you to run any program as PPL, which in the blog I used to run my ETW Tracer Sealighter to handle the Threat-Intelligence events.

But while PPLRunner served as a useful example of how to legitimately start a PPL Process, it would only work if Windows was put into either a Debug or ‘Test Signing’ mode. This is because to officially be able to run your code as PPL-AM you need to submit an ELAM or ‘Early Launch Anti Malware’ Driver to Microsoft to review and sign. Being an open source project I made instead of getting sleep, I had 0 interest in doing anything so formal.

But running Windows in debug or test signing mode might alter the behaviour of the malware or other programs, as they may (rightfully) notice and believe they are being observed, and not running on a ‘real’ system. So I wanted to see if there was other ways to get code running as PPL, legitimate or otherwise.

The non-secure security boundary

Back in 2018 Alex Ionescu and James Forshaw presented a series of talks, and blogs, covering many ways you could trick Windows into illegitimately running arbitrary code at the PPL level.

A number of these techniques remain unpatched to this day, mostly due to the fact that Microsoft don’t consider Admin-PPL a security boundary. Despite its purpose being a security boundary to protect certain processes from malicious SYSTEM-level access.

Then a few weeks ago Clément Labro released PPLDump. PPLDump uses one of the unpatched DLL hijack techniques Alex and James covered to launch PPL-elevated services.exe and trick it into loading an arbitrary DLL. This project and exploit is really neat, and I encourage you to also read Clément’s blog about the project, as well as the one from James where the technique was first discussed.

Taking the red and turning blue

PPLDump is an offensive tool that is used to dump credentials and memory from PPL protected processes such as lsass.exe. But I wanted to use the code for defensive purposes - I wanted to use Clément’s code to log the Threat-Intelligence ETW Provider without the need for a signed driver, or having to put Windows into Test Signing mode.

It turns out this was a super-smooth process. Clément’s code was well laid out that forking it and altering the code it injects was straight forward, so I only had to make some minor changes to enable it to load a DLL containing Sealighter.

Hook, line, and threading

One small hurdle I had to overcome was the while the exploit and Clément’s code got a DLL loaded into the PPL Process, only the DLLMain would be called before the process exited. While this was fine for Clément’s purposes of dumping process memory, doing anything complex inside of DLLMain is heavily discouraged, as you have no control over what DLLs get loaded in what order, which means if you attempt to call a function from another dll (such as ntdll) to risk crashing or deadlocking the process.

Sealighter makes use of COM, threading, and lots of other stuff that would make Raymond Chen nervous, so I made use of the Detours hooking library from Microsoft to hook the executable’s main() entrypoint function, ‘elevating’ our arbitrary code execution from running inside of a DLLMain to running once all DLLs had been loaded and all PE setup has occurred, right before the PE’s main entrypoint. Using Detours is super simple, the relevant code basically looks like this:

static int (WINAPI* TrueEntryPoint)(VOID);
int WINAPI HookedEntryPoint(VOID);
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
    if (dwReason == DLL_PROCESS_ATTACH) {
        // Find the PEs Entrypoint and hook it
        TrueEntryPoint = (int (WINAPI*)(VOID))DetourGetEntryPoint(NULL);
        DetourAttach(&(PVOID&)TrueEntryPoint, HookedEntryPoint);
    } else if (dwReason == DLL_PROCESS_DETACH) {
        // Remove hook
        DetourDetach(&(PVOID&)TrueEntryPoint, HookedEntryPoint);
    return TRUE;
int WINAPI HookedEntryPoint(VOID); {
    // You're now running as if you are the wmain() function of the PE
    // Once finished, call the real wmain() function
    return TrueEntryPoint();

Introducing: Sealighter-TI

The completed project is now on GitHub, which I’ve called Sealighter-TI.

Sealighter-TI will first use Alex’s/James’s/Clément’s DLL-hijack exploit to start a PPL-elevated services.exe with a custom DLL loaded into it. This DLL will then start an ETW Trace of the Microsoft-Windows-Threat-Intelligence Provider, logging the events out to the Windows Event Log to be viewed and read from non-PPL processes like PowerShell:

Picture of Sealighter injected into a ppl process

Picture of Sealighter injected into a ppl process

Sealighter-TI works without the need to sign any driver, and without having to put Windows in debug or test signing mode. The exploit it relies on could be fixed by Microsoft, and this would break Sealighter-TI, but it’s currently been 3 years without it being fixed, so Sealighter-TI may work for a while yet. Unless PPLDump elevates the bug in Microsoft’s queue, in which case it may need to be replaced with one of the other unpatched Admin->PPL exploits.

Further Reading

To learn more about PPL, I highly recommend reading these blogs and talks:

To learn more about ETW and the Threat Inteligence ETW Provider, I reccomend these blogs: