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:
- The presence of a SafeSEH handler table in the load configuration
- The
IMAGE_DLLCHARACTERISTICS_NO_SEHflag (if no SEH is used) - 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:
Without SafeSEH, an attacker who overflows the stack can:
- Overwrite the SEH handler pointer with a controlled address
- Trigger an exception (often the same overflow causes access violation)
- Exception dispatcher calls the corrupted handler
- 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.
Related Protections¶
| 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:
This is enabled by default for 32-bit binaries.
Project Properties¶
- Open Project Properties
- Navigate to Linker → Advanced
- Set "Image Has Safe Exception Handlers" to "Yes (/SAFESEH)"
CMake¶
For Binaries Without SEH¶
If your binary doesn't use SEH:
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¶
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