Skip to content
Persistenceintermediate

AppInit DLLs

Malware registers a DLL in the AppInit_DLLs registry value so it is loaded into nearly every user-mode process that links against User32.dll.

The AppInit_DLLs mechanism instructs User32.dll to load a list of arbitrary DLLs into the address space of every user-mode process that loads User32.dll during initialization — which is most GUI processes. When such a process starts, User32 reads the registry value and calls LoadLibrary on each path, giving the listed DLL code execution inside many unrelated processes at once.

This makes AppInit_DLLs both broad persistence and a system-wide injection primitive: a single registry write causes the payload to be mapped into Explorer, Office, browsers, and countless others. Because of this abuse, Microsoft deprecated the feature and, on systems with Secure Boot enabled, it is disabled outright; where it still functions, the LoadAppInit_DLLs flag must be set to 1 and (on signing-enforced builds) the listed DLLs must be code-signed.

The values live under HKLM and require administrative rights to modify, but a successful registration is exceptionally durable and noisy in its reach across processes.

How it works

Two values under a single key control the mechanism:

text
Key:   HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows
Name:  AppInit_DLLs        Data:  C:\Users\Public\inject.dll
Name:  LoadAppInit_DLLs    Data:  1

On 64-bit systems the WOW6432Node copy (HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Windows) governs 32-bit processes and is a commonly overlooked second location. The RequireSignedAppInit_DLLs value, when set to 0, relaxes signing enforcement — attackers may flip it to allow an unsigned payload. The load-bearing artifacts are a non-empty AppInit_DLLs path combined with LoadAppInit_DLLs = 1.

Detection & analysis

Static analysis:

  • In a captured sample, look for the subkey string CurrentVersion\Windows and the value names AppInit_DLLs/LoadAppInit_DLLs, plus the registry write APIs. A sample that sets RequireSignedAppInit_DLLs to 0 is a strong indicator of intent to load unsigned code.
  • Triage a live or imaged host with Autoruns (Sysinternals): the "AppInit" tab lists every registered DLL across both the native and WOW6432Node hives and flags unsigned entries.
  • Offline forensics: parse the SOFTWARE hive with RegRipper or Registry Explorer. On a clean system AppInit_DLLs is empty and LoadAppInit_DLLs is 0; any populated path is suspicious. Check both the native and WOW6432Node copies.

Dynamic analysis:

  • Run the sample under Procmon filtered on Path contains AppInit to capture the write. Then observe the broad fan-out: with Procmon Load Image events, the same DLL is mapped into many unrelated processes shortly after.
  • Sysmon Event ID 13 records the AppInit_DLLs value write; Event ID 7 (Image Loaded) shows the identical unsigned DLL loaded into numerous distinct host processes — the unusual breadth of the same module is the tell.

Detection rule hint:

Alert on any write to AppInit_DLLs (native or WOW6432Node), on LoadAppInit_DLLs being set to 1, or on RequireSignedAppInit_DLLs being set to 0. At runtime, flag a single unsigned DLL from a user-writable path being loaded into a large number of unrelated User32-based processes.

Votes

Comments(0)