How ASLR, DEP, and stack canaries make exploitation harder — the mechanism behind each mitigation, its known bypass techniques, and why understanding them helps analysts recognise evasion in the wild.
⚡ Quick Bite · 40s
Modern OS defences — ASLR randomizing memory addresses, DEP blocking code execution, ROP chains bypassing DEP, and Stack Canaries detecting buffer overflows before execution.
Watch this 40-second summary before diving into the full article. Sign in to earn 5 leaderboard points.
Modern operating systems do not rely on programmers writing bug-free code. They deploy hardware and software mitigations that make exploitation harder even when a vulnerability exists.
Analysts need to understand these mitigations because:
ASLR randomises the base addresses of the executable image, stack, heap, and loaded DLLs on each process execution. An attacker who discovers a buffer overflow cannot hardcode a jump address because the target address changes on every run.
| Architecture | Entropy (Stack) | Brute-force Feasibility |
|---|---|---|
| 32-bit Windows | 8–9 bits | Feasible in seconds to minutes |
| 64-bit Windows (HEASLR) | 17+ bits | Infeasible |
| 64-bit Linux (PIE) | 28+ bits | Infeasible |
32-bit ASLR is weak. Malware targeting 32-bit systems sometimes brute-forces ASLR by repeatedly crashing and restarting the target process until a predictable address is hit.
| Technique | Mechanism |
|---|---|
| Information disclosure | Leak a pointer to calculate actual base address |
| Partial overwrite | Modify only the lower bytes (unaffected by ASLR randomisation) |
| Non-ASLR modules | Target DLLs compiled without /DYNAMICBASE flag |
| Brute force | Feasible on 32-bit systems with low entropy |
| Heap spray | Fill large memory region with shellcode — increases probability of hitting it |
In dynamic analysis, a crash followed by a retry loop in the malware suggests ASLR brute-forcing. An information disclosure followed by a calculated jump target suggests a leak-based bypass.
DEP marks the stack and heap as non-executable. The CPU refuses to execute instructions fetched from pages without the Execute permission, enforced via the NX (AMD) or XD (Intel) bit in page table entries.
Even if an attacker injects shellcode into a data region, the CPU raises an access violation when attempting to execute bytes from a non-executable page.
ROP chains together small snippets of existing executable code called gadgets — sequences ending in RET — that already exist in loaded modules.
Stack layout for a ROP chain:
┌──────────────────────────────┐
│ Address of gadget 1 │ ← return address (overwritten)
│ Address of gadget 2 │ ← popped by gadget 1's RET
│ Address of gadget 3 │ ← popped by gadget 2's RET
│ Address of VirtualProtect() │ ← called to make shellcode executable
│ Arguments to VirtualProtect │
└──────────────────────────────┘
No injected code executes — only existing code in executable regions. DEP is bypassed entirely.
ROP gadgets look like this in disassembly:
pop eax ; ← this is the gadget
ret ; ← RET chains to next gadget address on stack
Finding ROP gadgets in loaded DLLs is automated by tools like ROPgadget and mona.py.
DEP prevents code injection. ASLR prevents reliable gadget addressing. Defeating both requires:
Malware that uses both bypass techniques is sophisticated and likely from a professional threat actor.
A random value — the canary — is placed between local buffers and the saved return address during function prologue. Before RET executes, the epilogue verifies the canary value. If corrupted, the process terminates immediately.
Stack layout with canary:
┌─────────────────────────┐
│ Return Address │ ← target of overflow
│ Saved EBP │
│ Stack canary (random) │ ← verified before RET
│ Local buffer │ ← overflow starts here
└─────────────────────────┘
An overflow must corrupt the canary before reaching the return address — triggering immediate termination.
Requires knowing the canary value in advance via an information disclosure vulnerability — reading the canary value from memory before triggering the overflow, then including the correct value in the exploit payload.
| Compiler | Flag | Notes |
|---|---|---|
| MSVC | /GS | Default since Visual Studio 2003 |
| GCC | -fstack-protector | Protects functions with arrays |
| GCC | -fstack-protector-strong | Protects more functions |
| Mitigation | Defeats | Bypass Technique |
|---|---|---|
| ASLR | Hardcoded addresses | Info leak, brute force (32-bit), non-ASLR modules |
| DEP/NX | Shellcode injection | ROP chain using existing executable code |
| Stack canary | Return address overwrite | Info leak to read canary value first |
ASLR and DEP are most effective together. Bypassing both requires an information leak and a ROP chain — significantly raising the bar for exploitation.
Sign in to mark this article as read and track your progress.