AD2015: EnableHighEntropyVirtualAddresses¶
Summary¶
| Property | Value |
|---|---|
| ID | AD2015 |
| Name | EnableHighEntropyVirtualAddresses |
| Category | Security |
| Severity | Error |
| Applies to | PE (Windows) - 64-bit binaries |
Description¶
Binaries should be marked as high entropy Address Space Layout Randomization (ASLR) compatible. High entropy allows ASLR to be more effective in mitigating memory corruption vulnerabilities.
Standard ASLR on 64-bit systems provides about 17 bits of entropy. High entropy ASLR increases this to approximately 24 bits, making brute-force attacks infeasible.
How It Works¶
The rule checks for the IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag (0x0020) in the PE optional header's DLL characteristics field.
Why This Matters¶
High-entropy ASLR exponentially increases the difficulty of brute-force attacks against memory layout. The difference between standard and high-entropy ASLR can mean the difference between a successful attack and an impossible one.
The Mathematics of Entropy¶
ASLR security is measured in bits of entropy:
| Configuration | Entropy | Possible Locations | Brute-force at 1000/sec |
|---|---|---|---|
| No ASLR | 0 bits | 1 | Instant |
| 32-bit ASLR | ~16 bits | ~65,536 | ~1 minute |
| 64-bit standard | ~17 bits | ~131,072 | ~2 minutes |
| 64-bit high entropy | ~24 bits | ~16 million | ~4.5 hours |
| Theoretical max | ~47 bits | ~140 trillion | ~4,400 years |
Each additional bit of entropy doubles the attack difficulty.
Why 64-bit Systems Default to Low Entropy¶
For backward compatibility, 64-bit Windows limits ASLR entropy by default. High-entropy ASLR opts binaries into using the full 64-bit address space, but this requires:
- The binary to be marked compatible (
/HIGHENTROPYVA) - All pointers to be valid 64-bit values (not truncated)
- No assumptions about address ranges
Brute-Force Attack Scenarios¶
Scenario 1: Local brute-force
Attacker can crash and restart service repeatedly
Standard ASLR: ~65K attempts = minutes to crack
High-entropy: ~16M attempts = impractical in many scenarios
Scenario 2: Network service
Each connection attempt reveals success/failure
Network latency limits to ~100 attempts/sec
High-entropy: ~45 hours average, likely to be noticed
Scenario 3: Combined with info leak
Partial pointer leak gives some bits
High-entropy: Even with leak, more bits remain unknown
Standard: Leak may completely defeat ASLR
Compatibility Considerations¶
High-entropy ASLR can break code that:
- Truncates pointers:
int ptr = (int)address;loses high bits - Uses signed comparison:
if (ptr1 > ptr2)can fail for high addresses - Stores addresses in 32-bit fields: Database schemas, file formats
Modern 64-bit code should not have these issues. Legacy code may need updates.
Performance Impact¶
High-entropy ASLR has zero runtime performance impact. The only effect is on where memory is allocated—the CPU doesn't care whether addresses are above or below any threshold.
Combined with Other Mitigations¶
| Mitigation | Effect on Attacker |
|---|---|
| High-entropy ASLR | Must find ~24 bits of address |
| + CFG | Can't call arbitrary addresses |
| + CET | Can't manipulate returns |
| Combined | Exploitation becomes extremely difficult |
Resolution¶
Enable High Entropy ASLR¶
Linker flag:
This is enabled by default for 64-bit binaries in modern Visual Studio. Ensure it's not disabled:
Project Properties¶
- Open Project Properties
- Navigate to Linker → Advanced
- Set "High Entropy ASLR" to "Yes (/HIGHENTROPYVA)"
CMake¶
When to Suppress¶
This rule may be suppressed for:
- 32-bit binaries: High entropy ASLR is 64-bit only
- Large address space requirements: Some applications need predictable addresses
- Pointer truncation issues: Legacy code that truncates pointers to 32 bits
Caveats¶
- Only applies to 64-bit binaries
- Requires
/DYNAMICBASEto also be enabled - May break code that assumes addresses fit in 32 bits
- Third-party libraries must also be compatible
Entropy Comparison¶
| Configuration | Entropy | Possible Addresses |
|---|---|---|
| No ASLR | 0 bits | 1 (fixed) |
| Standard ASLR | ~17 bits | ~131,000 |
| High Entropy ASLR | ~24 bits | ~16,000,000 |
Checking Compatibility¶
Before enabling, verify your code doesn't:
// Bad - truncates 64-bit pointer
DWORD ptr32 = (DWORD)pointer;
// Bad - assumes address fits in 32 bits
struct { DWORD address; } legacy;
// Good - use proper pointer sizes
DWORD_PTR ptr = (DWORD_PTR)pointer;