Persistence techniques

← maldev README · docs/index

The persistence/* package tree groups Windows-only mechanisms that re-launch an implant across reboots and user logons. The Mechanism interface is the composition primitive: each sub-package returns a Mechanism, and InstallAll / VerifyAll / UninstallAll operate on a flat slice — operators typically install two or three mechanisms in parallel so failure of any single one (cleanup sweep, AV remediation, EDR auto-roll-back) does not lose persistence.

flowchart TB
    subgraph trig [Triggers]
        LOGON[user logon]
        BOOT[boot]
        SCHED[schedule / time]
        CLICK[user execution]
    end
    subgraph mechs [persistence/*]
        REG[registry<br>HKCU + HKLM<br>Run / RunOnce]
        ST[startup<br>StartUp-folder LNK]
        SCHEDP[scheduler<br>COM ITaskService]
        SVC[service<br>SCM SYSTEM]
        ACC[account<br>local user + admin]
        LNK[lnk<br>shortcut primitive]
    end
    subgraph compose [Composition]
        IFACE[Mechanism interface]
        ALL[InstallAll / VerifyAll / UninstallAll]
    end
    LOGON --> REG
    LOGON --> ST
    LOGON --> SCHEDP
    BOOT --> SVC
    BOOT --> SCHEDP
    SCHED --> SCHEDP
    CLICK --> LNK
    ACC -. companion to .-> SVC
    LNK -. underlying primitive of .-> ST
    REG --> IFACE
    ST --> IFACE
    SCHEDP --> IFACE
    SVC --> IFACE
    IFACE --> ALL

Packages

PackageTech pageDetectionOne-liner
persistence/registryregistry.mdmoderateHKCU + HKLM Run / RunOnce key persistence
persistence/startupstartup-folder.mdmoderateStartUp-folder LNK persistence (user + machine)
persistence/schedulertask-scheduler.mdmoderateCOM-based scheduled tasks; logon / startup / daily / time triggers
persistence/serviceservice.mdnoisyWindows service via SCM (SYSTEM-scope)
persistence/lnklnk.mdquietUnderlying LNK creation primitive (used by startup, also for T1204.002 user-execution traps)
persistence/accountaccount.mdnoisyLocal user account add / delete / group membership

Quick decision tree

You want to…Use
…survive a reboot, no adminregistry.RunKey(HiveCurrentUser, …) or startup.Shortcut
…survive a reboot, machine-wideregistry.RunKey(HiveLocalMachine, …) or startup.InstallMachine
…trigger before user logon (boot / startup)scheduler with WithTriggerStartup or service
…schedule recurring callbacksscheduler.Create with WithTriggerDaily
…run as SYSTEMservice or scheduler with startup trigger
…compose multiple mechanisms with redundancypersistence.InstallAll
…leave a credential that survives implant removalaccount.Add + SetAdmin (loud)
…drop a user-execution trap (Desktop / Quick Launch)lnk.New

Layered redundancy recipe

The canonical "redundant persistence" pattern installs two mechanisms with different telemetry profiles. Loss of one does not lose persistence; the noisier one provides reach, the quieter one provides resilience.

mechs := []persistence.Mechanism{
    // Loud + reach: SYSTEM-scope service, runs at boot.
    service.Service(&service.Config{
        Name:      "WinUpdate",
        BinPath:   `C:\ProgramData\Microsoft\winupdate.exe`,
        StartType: service.StartAuto,
    }),
    // Quiet + resilience: HKCU Run-key, runs at user logon.
    registry.RunKey(registry.HiveCurrentUser, registry.KeyRun,
        "WinUpdateBackup",
        `C:\ProgramData\Microsoft\winupdate.exe`),
}
errs := persistence.InstallAll(mechs)

MITRE ATT&CK

T-IDNamePackagesD3FEND counter
T1547.001Boot or Logon Autostart Execution: Registry Run Keys / Startup Folderpersistence/registry, persistence/startupD3-SICA, D3-FCA
T1547.009Shortcut Modificationpersistence/lnk, persistence/startupD3-FCA
T1053.005Scheduled Task/Job: Scheduled Taskpersistence/schedulerD3-SCA
T1543.003Create or Modify System Process: Windows Servicepersistence/serviceD3-PSA, D3-SICA
T1136.001Create Account: Local Accountpersistence/accountD3-LAM
T1098Account Manipulationpersistence/account (group changes)D3-UAP
T1204.002User Execution: Malicious Filepersistence/lnk (Desktop / Quick Launch traps)D3-FCA

See also