Skip to content

AD2013: InitializeStackProtection

Summary

Property Value
ID AD2013
Name InitializeStackProtection
Category Security
Severity Error
Applies to PE (Windows)

Description

Binaries should properly initialize the stack protection cookie at startup. The __security_init_cookie function randomizes the cookie value, making it harder for attackers to predict and bypass stack buffer overflow protection.

How It Works

The rule checks that:

  1. The binary has a security cookie configured in load config
  2. The CRT properly initializes the cookie via __security_init_cookie
  3. For DLLs, the entry point calls the initialization function

Standard CRT startup code automatically calls __security_init_cookie before main() or DllMain().

Why This Matters

The security cookie must be randomized at process startup before any protected functions execute. Without proper initialization, the well-known default cookie value provides zero protection against stack overflow attacks.

The Initialization Race

There's a critical window at process startup:

Process Timeline:

[Start] → [CRT Init] → [Cookie Init] → [main()] → [Your Code]
    |           |            |
    v           v            v
  Cookie =   Cookie =    Cookie =
  default    default     random
  (known)    (known)     (secure)

Any code running before cookie initialization has only the known default cookie—effectively no protection.

Default cookie values are public knowledge:

Architecture Default (Well-Known) After Init (Random)
x86 0xBB40E64E Random 32-bit
x64 0x00002B992DDFA232 Random 64-bit

Any attacker can include these defaults in their exploit payload if initialization hasn't occurred.

Common Initialization Failures

  1. Custom entry points: Using /ENTRY:MyMain without calling __security_init_cookie
  2. Minimal CRT: Using /NODEFAULTLIB and not providing initialization
  3. DLL without DllMain: Some DLL patterns skip standard initialization
  4. Early execution: Code running from TLS callbacks or static constructors

Correct Initialization Pattern

For custom entry points, initialization must be the first operation:

extern "C" void __security_init_cookie(void);

void WINAPI MyCustomEntryPoint() {
    // FIRST: Initialize security cookie
    __security_init_cookie();

    // THEN: Everything else
    InitializeHeap();
    LoadConfiguration();
    MyMain();
}

DLL Considerations

DLLs must initialize their cookie on DLL_PROCESS_ATTACH:

BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved) {
    if (reason == DLL_PROCESS_ATTACH) {
        __security_init_cookie();  // Before any other code
        // ... rest of initialization
    }
    return TRUE;
}

Entropy Sources

__security_init_cookie gathers entropy from:

  • System time (high-resolution)
  • Process ID
  • Thread ID
  • Performance counter
  • Stack pointer

This provides sufficient randomness to make guessing infeasible.

Resolution

Use Standard CRT

The simplest fix is to use the standard CRT, which handles initialization automatically:

// Standard entry point - CRT handles cookie init
int main() {
    // __security_init_cookie already called by CRT
    return 0;
}

Custom Entry Points

If you use a custom entry point, initialize the cookie first:

extern "C" void __security_init_cookie(void);

// Custom entry point
void WINAPI MyEntryPoint() {
    __security_init_cookie();  // MUST be first

    // Rest of initialization
    MyMain();
}

DLL Entry Points

For DLLs with custom entry points:

extern "C" void __security_init_cookie(void);

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
    if (fdwReason == DLL_PROCESS_ATTACH) {
        __security_init_cookie();  // Initialize before any work
    }
    return TRUE;
}

When to Suppress

This rule may be suppressed for:

  • No CRT binaries: Intentionally avoiding CRT (must handle security manually)
  • Boot code: Pre-OS initialization code
  • Compatibility modes: Very specific legacy requirements

Caveats

  • Cookie initialization must happen before any /GS-protected function runs
  • DLLs loaded via LoadLibrary after process start still need initialization
  • Static CRT linking includes the initialization automatically

Initialization Timing

Process Start:
1. Loader maps executable
2. Entry point called (e.g., mainCRTStartup)
3. __security_init_cookie() called ← CRITICAL
4. CRT initialization
5. main() called
6. Functions with /GS now have valid cookie

References