Winlogon Userinit & Helper DLL
Overview
Winlogon - winlogon.exe, the secure logon manager - loads a fixed set of components at every
interactive logon. Two of those are attacker-writable, which is what makes Winlogon a
persistence target. The Userinit value under HKLM\...\Winlogon names the executable the
logon manager runs after authentication; the default is C:\Windows\System32\Userinit.exe. The
value is a comma-separated list, and winlogon will LoadLibrary each entry - so appending a
second path loads an arbitrary DLL before the desktop even appears.
The other vector is the Winlogon notification (Notify) package. A signed DLL registered under
HKLM\...\Winlogon\Notify is called by winlogon at logon and logoff through its exported SPI
functions. Because the OS loads it from a registry-declared path, it runs with the integrity of
the logon manager - winlogon.exe is SYSTEM, so the helper is effectively SYSTEM too, and
it is loaded before most userland persistence can fire.
Winlogon persistence runs in the logon manager, not in a new process. A broken helper DLL can hang the logon, and a helper that references a missing export can take the session down with it. This is the trade-off: higher integrity and earlier execution than a run key, at the cost of being inside a critical system process.
The call chain
- 1Target the Winlogon keyHKLM ...\Winlogon Userinit, Shell, or a Notify subkey under the same hive.
- 2Append or register the payloadAdd a DLL to the comma-separated Userinit list, or register a Notify package.
- 3User logs onWinlogon starts and loads Userinit, which LoadLibrary's each entry in the list.
- 4Payload runs in winlogonThe DLL's DllMain executes inside winlogon.exe for the whole session.
Reference implementation
The three vectors, and what each one requires.
| Vector | Key / location | Privilege | Runs as |
|---|---|---|---|
| Userinit append | HKLM\...\Winlogon Userinit |
Admin | winlogon (SYSTEM) |
| Shell override | HKLM\...\Winlogon Shell |
Admin | winlogon (SYSTEM) |
| Notify package | HKLM\...\Winlogon\Notify\<name> |
Admin | winlogon (SYSTEM) |
The Userinit append is the most common. The value becomes a comma-terminated list and
winlogon loads each entry.
Windows Registry Editor Version 5.00 # the stock value is C:\\Windows\\system32\\Userinit.exe, # appending a second entry makes winlogon LoadLibrary your DLL too [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon] "Userinit"="C:\\Windows\\system32\\Userinit.exe, C:\\ProgramData\\.u\\hook.dll,"
Windows Registry Editor Version 5.00
# the stock value is C:\\Windows\\system32\\Userinit.exe,
# appending a second entry makes winlogon LoadLibrary your DLL too
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon]
"Userinit"="C:\\Windows\\system32\\Userinit.exe, C:\\ProgramData\\.u\\hook.dll,"The trailing comma after each entry is load-bearing. winlogon splits the value on commas and
expects each element to be terminated; dropping the final comma is the most common reason an
appended helper silently never loads.
Verifying in the lab
Log out and back in. The helper is loaded into winlogon.exe, not launched as its own process.
Sysmon records the image load; there is no process-create for the DLL.
# EID 7 at logon (no EID 1 - it is a load, not a spawn): # Image loaded: C:\ProgramData\.u\hook.dll # Process: winlogon.exe # ^ loaded into the logon manager <-- the artifact > reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v Userinit Userinit REG_SZ C:\Windows\system32\Userinit.exe, C:\ProgramData\.u\hook.dll,
# EID 7 at logon (no EID 1 - it is a load, not a spawn):
# Image loaded: C:\ProgramData\.u\hook.dll
# Process: winlogon.exe
# ^ loaded into the logon manager <-- the artifact
> reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v Userinit
Userinit REG_SZ C:\Windows\system32\Userinit.exe, C:\ProgramData\.u\hook.dll,Detection
The signature is a change to a winlogon registry value, or a non-system DLL loading into the
logon manager at logon.
Rank them: the EID 13 value-set rule on the Winlogon key is the earliest continuous control and
catches both the Userinit append and a Notify registration. The EID 7 image-load rule confirms
execution inside winlogon.exe and is the cleaner alert for triage. The behavioural list-length
check catches appended helpers that the path-based rules can miss.