Windows special-folder paths
TL;DR
Resolve Windows special folder paths (Desktop, AppData,
Startup, Program Files, …) via SHGetSpecialFolderPathW. Used
by persistence/startup for StartUp-folder paths, by
credentials/lsassdump for %SystemRoot%\System32\ntoskrnl.exe,
and by any payload that needs a per-user / per-machine
well-known path.
Primer
Windows uses CSIDL (Constant Special ID List) values to
identify well-known folders abstractly. SHGetSpecialFolderPathW
takes a CSIDL constant and returns the resolved filesystem path,
handling per-user / per-machine differences and folder
redirection in domain environments transparently.
The function is technically deprecated in favor of
SHGetKnownFolderPath (Vista+, KNOWNFOLDERID enum), but the
older API remains widely supported and avoids COM
initialization overhead.
API → godoc
pkg.go.dev/github.com/oioio-space/maldev/recon/folder is the authoritative
reference for every exported symbol. This page teaches the
concepts; the godoc is the specification.
Examples
Simple — modern KNOWNFOLDERID
import (
"github.com/oioio-space/maldev/recon/folder"
"golang.org/x/sys/windows"
)
appdata, _ := folder.GetKnown(windows.FOLDERID_RoamingAppData, 0)
downloads, _ := folder.GetKnown(windows.FOLDERID_Downloads, 0)
system, _ := folder.GetKnown(windows.FOLDERID_System, 0)
// Force creation (KFF_CREATE) when staging a per-user drop directory:
stage, _ := folder.GetKnown(windows.FOLDERID_LocalAppData, windows.KF_FLAG_CREATE)
Simple — legacy CSIDL
appdata := folder.Get(folder.CSIDL_APPDATA, false)
startup := folder.Get(folder.CSIDL_STARTUP, false)
system := folder.Get(folder.CSIDL_SYSTEM, false)
Composed — feed persistence
import (
"path/filepath"
"github.com/oioio-space/maldev/recon/folder"
)
implant := filepath.Join(
folder.Get(folder.CSIDL_LOCAL_APPDATA, false),
"Microsoft", "OneDrive", "Update", "winupdate.exe",
)
Advanced — resolve ntoskrnl path for kernel-driver work
ntos := filepath.Join(
folder.Get(folder.CSIDL_SYSTEM, false),
"ntoskrnl.exe",
)
// feeds credentials/lsassdump.DiscoverProtectionOffset(ntos, opener)
OPSEC & Detection
| Artefact | Where defenders look |
|---|---|
SHGetSpecialFolderPathW calls | Universal Win32 API — invisible |
| Subsequent file writes to resolved paths | EDR file-write telemetry; flag depends on the path |
D3FEND counters: none specific — primitive itself is universally legitimate.
Hardening: none — the call is invisible. Hardening is at the consumer (the writes the path drives).
MITRE ATT&CK
| T-ID | Name | Sub-coverage | D3FEND counter |
|---|---|---|---|
| T1083 | File and Directory Discovery | full | — |
Limitations
- CSIDL is the legacy path. Microsoft recommends
KNOWNFOLDERID for new code. The package now ships both:
use
GetKnownfor new callers;Getstays for backwards compatibility. KNOWNFOLDERID also exposes folders the legacy CSIDL set cannot resolve (FOLDERID_Downloads, third-party Shell extensions). GetKnownreturns API-allocated PWSTR. The wrapper frees it viaCoTaskMemFreeon every call — never returns a borrowed buffer the caller must clean up.- MAX_PATH cap on
Getonly. The legacy path truncates paths longer than 260 chars (Get);GetKnownis uncapped. - Some virtual folders return empty.
CSIDL_NETWORK,CSIDL_PRINTERS, and similar non-filesystem virtual folders return empty strings. - Folder redirection is opaque. Domain-joined hosts with redirected user folders return the redirected (network) path, not the local cached one — operators relying on local-only paths must validate.
See also
persistence/startup— primary consumer (StartUp folder).credentials/lsassdump— consumer (System32 path resolution).recon/drive— sibling drive enumeration.- Operator path.
- Detection eng path.