Skip to content

AD2018: EnableSafeSEH

Summary

Property Value
ID AD2018
Name EnableSafeSEH
Category Security
Severity Error
Applies to PE (Windows) - 32-bit binaries only

Description

Structured Exception Handling (SEH) is a mechanism for handling both hardware and software exceptions on Windows. SEH-based exploitation has been a common attack vector.

SafeSEH is a linker option (/SAFESEH) that creates a table of valid exception handlers that is validated by the operating system before an exception handler is called. This helps prevent attackers from redirecting execution through corrupted exception handlers.

How It Works

The rule checks for:

  1. The presence of a SafeSEH handler table in the load configuration
  2. The IMAGE_DLLCHARACTERISTICS_NO_SEH flag (if no SEH is used)
  3. Proper registration of all exception handlers

Why This Matters

Structured Exception Handling (SEH) exploitation was once the most reliable Windows attack technique. SafeSEH was developed specifically to counter this threat, and its absence on 32-bit systems leaves a well-documented attack path open.

The SEH Exploitation Technique

SEH provides a linked list of exception handlers on the stack:

Stack:
[Local vars][SEH Record][Next SEH Record]...
               |
               +--> Handler pointer

Without SafeSEH, an attacker who overflows the stack can:

  1. Overwrite the SEH handler pointer with a controlled address
  2. Trigger an exception (often the same overflow causes access violation)
  3. Exception dispatcher calls the corrupted handler
  4. Attacker gains code execution

This was particularly powerful because: - No need to precisely overwrite return address - Exception handler called before /GS cookie check - Attacker controls exactly when handler is invoked

Historical Significance

SEH exploitation dominated Windows security from 2003-2012:

Year Development
2003 SEH overwrites become primary technique
2006 SafeSEH introduced (Windows XP SP2)
2009 SEHOP adds additional protection
2012 64-bit dominance reduces impact

How SafeSEH Works

SafeSEH creates a table of valid exception handlers at compile time:

Before exception dispatch:
1. Windows checks if handler is in SafeSEH table
2. If not in table → terminate process
3. If in table → call handler normally

An attacker cannot add their shellcode to this table, so SEH overwrites become useless.

Why This Only Affects 32-bit

64-bit Windows uses a completely different exception handling model:

Architecture Exception Model SEH Exploitation
32-bit (x86) Stack-based SEH Possible without SafeSEH
64-bit (x64) Table-based Not applicable

On x64, exception handlers are stored in read-only tables in the binary, not on the stack.

Protection Purpose
SafeSEH Validates handler is in table
SEHOP Validates SEH chain integrity
CFG Validates indirect calls generally
ASLR Makes handler addresses unpredictable

Modern Relevance

While 64-bit systems have made SEH exploitation obsolete, 32-bit code still runs:

  • Legacy applications
  • WoW64 (32-bit on 64-bit Windows)
  • Embedded Windows systems
  • Old hardware compatibility

For any 32-bit Windows binary, SafeSEH remains essential.

Performance Considerations

SafeSEH has zero runtime overhead for normal execution:

Aspect Impact
Normal execution None
Exception handling Minimal table lookup
Binary size Small handler table
Startup time None

Why there's no overhead: - SafeSEH validation only occurs during exception dispatch - Normal code paths never invoke the validator - The handler table is read-only data, not code

Exception dispatch impact: - Adds one table lookup before calling handler - Cost is negligible compared to exception handling overhead - Only affects the already-slow exception path

There is no performance reason to disable SafeSEH.

Resolution

Enable SafeSEH

Linker flag:

link.exe /SAFESEH ...

This is enabled by default for 32-bit binaries.

Project Properties

  1. Open Project Properties
  2. Navigate to Linker → Advanced
  3. Set "Image Has Safe Exception Handlers" to "Yes (/SAFESEH)"

CMake

if(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 4)
    add_link_options(/SAFESEH)
endif()

For Binaries Without SEH

If your binary doesn't use SEH:

link.exe /SAFESEH:NO ...

This sets the IMAGE_DLLCHARACTERISTICS_NO_SEH flag, indicating no handlers to validate.

When to Suppress

This rule is suppressed automatically for:

  • 64-bit binaries: Use table-based exception handling instead
  • ARM binaries: Different exception model

May be manually suppressed for:

  • Legacy assembly: Inline assembly with custom SEH
  • Mixed object files: When linking old .obj files

Caveats

  • Only applies to 32-bit x86 binaries
  • All linked .obj files must be SafeSEH compatible
  • Old libraries may not have SafeSEH data

Checking SafeSEH Compatibility

# Check if a library is SafeSEH compatible
dumpbin /LOADCONFIG library.lib

SEH Exploitation Background

Classic SEH Attack:
1. Buffer overflow corrupts SEH handler pointer
2. Attacker triggers exception
3. Corrupted handler called → shellcode execution

With SafeSEH:
1. Buffer overflow corrupts SEH handler pointer
2. Attacker triggers exception
3. OS validates handler against SafeSEH table
4. Invalid handler detected → process terminated

References