Skip to content
λmaldev wiki/
pagesAppInit_DLLs & AppCertDlls
T1547.001WindowsRegistryDLLWinlogonExplorer

AppInit_DLLs & AppCertDlls

updated 2026-09-048 min readthehackersbrain
Authorized use only. This material is published for detection engineering, malware analysis and authorized red-team engagements. Running these techniques against systems you do not own or have written permission to test is illegal.

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.

Caution.

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

  1. 1
    Write AppInit_DLLs
    A value under Windows\Load with LoadLibrary=1 makes Explorer load the DLL at user logon.
  2. 2
    or install AppCertDlls
    A value under Image File Execution Options\AppCertDlls makes the loader call into the DLL before a process starts.
  3. 3
    The payload lands in the host
    AppInit_DLLs lands in explorer.exe; AppCertDlls can land in every process unless filtered out.
  4. 4
    Code runs at logon or process start
    DllMain, 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.ps1PowerShell
# 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

The 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.

appcert.ps1PowerShell
# 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.

appcert_stub.cC
#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

Verifying 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.

lab_check
# 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

Detection

The registry write is the setup; the module load is the confirmation.

SYSMON EID 13
AppInit_DLLs is set to a non-empty value; on a clean system the value is empty or absent.
SYSMON EID 7
A DLL outside the system32 directory is loaded into explorer.exe at user logon.
SYSMON EID 13
A value is created under Image File Execution Options\AppCertDlls.
BEHAVIOURAL
The same non-system DLL appears across a broad set of unrelated processes shortly after a registry change.

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.

Was this page useful?edit this page ↗