DEV Community

Cover image for What Is ASLR? How Does Randomizing Memory Addresses Stop Exploitation?
Aditya Sharma
Aditya Sharma

Posted on

What Is ASLR? How Does Randomizing Memory Addresses Stop Exploitation?

What if the memory address an attacker needs today isn't the same address tomorrow?

That question is the core idea behind Address Space Layout Randomization. Before getting into how it works, it helps to understand the problem it addresses.

Many exploitation techniques rely on knowing where things are in memory. If you can corrupt memory in a running process, that corruption is only useful if you can direct it somewhere meaningful. Overwrite the right data, redirect execution to the right address, or interfere with the right memory region. Without knowing where those things are, the attacker has a harder time turning a vulnerability into reliable controlled behavior.

ASLR doesn't fix the underlying vulnerability. The buggy code still exists. What ASLR does is make the memory layout unpredictable, introducing uncertainty that makes reliable exploitation significantly harder.


Understanding Virtual Memory First

To understand ASLR, you need a clear picture of what "address space" means and what ASLR is actually randomizing.

When a program runs, it doesn't directly address physical RAM. The operating system gives it a virtual address space, a range of addresses the process can use as if it had access to a large, contiguous block of memory. The operating system and hardware (through the memory management unit) translate those virtual addresses to actual physical memory locations at runtime.

Process
   |
   v
Virtual Address Space
   |
   v
Virtual-to-Physical Mapping (page table)
   |
   v
Physical Memory
Enter fullscreen mode Exit fullscreen mode

Each process has its own virtual address space. Two different processes can use the same virtual addresses while mapping to entirely different physical memory. This is why one process can't accidentally read another's memory: the same virtual address means different physical memory in different processes.

ASLR works within this virtual address space layer. It changes where different regions of a process's virtual address space are placed each time the program loads.


A Process's Memory Layout

A running process typically has several distinct memory regions, each serving a different purpose:

High Addresses
------------------
|    Stack       |   Local variables, return state, function call frames
------------------
|     ...        |
------------------
| Shared Libs    |   Dynamically linked code (libc, etc.)
------------------
|     Heap       |   Dynamically allocated memory
------------------
| Data / BSS     |   Global/static variables
------------------
|    Code        |   Program instructions (text segment)
------------------
Low Addresses
Enter fullscreen mode Exit fullscreen mode

The exact layout depends on the operating system, architecture, executable format, linker, and loader. This is a conceptual model, not a universal specification. But the general principle holds: different types of data and code live in different regions of the virtual address space.

Without ASLR, these regions tend to load at fixed or predictable base addresses. The code segment starts at the same place every time. The stack begins at the same place. Shared libraries map to the same addresses. An attacker who studies the binary or observes memory once can often predict exactly where things will be in future runs.


Why Predictable Addresses Help Attackers

Consider a memory corruption vulnerability, a type confusion bug, an out-of-bounds write, a buffer overflow. The vulnerability lets an attacker write data somewhere in memory. That's a starting point, not an end goal. The question is what that write can accomplish.

Exploitation techniques often need to redirect execution, corrupt data structures at specific locations, or reference existing code that does something useful. All of these require knowing the addresses involved.

Without ASLR:

Run 1 → libc at address 0xf7400000
Run 2 → libc at address 0xf7400000
Run 3 → libc at address 0xf7400000
Enter fullscreen mode Exit fullscreen mode

The attacker can work out those addresses through static analysis, running the application locally, or reading public information about the system. Once known, they stay known.

With ASLR:

Run 1 → libc at address 0xf7312000
Run 2 → libc at address 0xb76a1000
Run 3 → libc at address 0xf4a23000
Enter fullscreen mode Exit fullscreen mode

The attacker's knowledge of where libc was in one execution doesn't help for the next. They face a new problem: before exploiting the vulnerability, they need to discover the current layout.


What ASLR Actually Randomizes

ASLR randomizes the base addresses of major process memory regions when the process loads. Depending on the operating system, configuration, and whether the executable is built with appropriate support, this can include:

The stack. Where the stack begins in virtual memory changes between runs. This affects the addresses of local variables, saved return state, and other stack-based structures.

The heap. Where the dynamic memory allocator starts its managed region changes between runs.

Shared libraries. Dynamically linked libraries are mapped into the process address space at load time. With ASLR, their base addresses are randomized, changing the addresses of all the code and data they contain.

Memory-mapped regions. Files or other resources mapped into memory also receive randomized addresses.

The main executable. This only receives randomization if the executable is built as a Position Independent Executable (PIE), discussed next.


PIE: Randomizing the Executable Itself

A normal compiled executable often assumes it will be loaded at a specific base address. Instructions in the binary may use hardcoded addresses relative to where the program expects to be. If the operating system tries to load it at a different address, the program breaks.

A Position Independent Executable is built differently. The compiler and linker generate code that works correctly regardless of where it is loaded in virtual memory. Instead of hardcoded absolute addresses, the code uses position-relative addressing. The loader can place the executable at any address and everything still functions.

This distinction matters:

ASLR = the OS mechanism that randomizes load addresses at runtime

PIE = the executable property that allows the main binary's base address to be randomized
Enter fullscreen mode Exit fullscreen mode

ASLR can randomize shared libraries, the stack, and the heap without PIE. But without PIE, the main executable's code and data often remain at a predictable base address. That gives an attacker a fixed anchor point in an otherwise randomized address space.

Modern build toolchains default to PIE for executables on many platforms, but this isn't universal. Older software, software built with older toolchains, or software that explicitly disables PIE may lack it.


Entropy: How Much Randomization Is Enough?

Randomization is only as strong as the range of possible positions. If the stack can only land in one of a small number of locations, an attacker might attempt every possibility, a strategy sometimes called brute-forcing the layout.

The number of possible positions is described by the entropy: how many bits of randomness are applied to each region. With n bits of entropy, there are 2^n possible base addresses.

On 32-bit systems, the total virtual address space is limited (4 gigabytes, or 32 bits). Allocating space for code, libraries, stack, and heap leaves relatively little room for randomization. A region might have only 16 bits of entropy for its base address, meaning 65,536 possible positions. Still an obstacle, but potentially feasible to brute-force in certain scenarios.

On 64-bit systems, the virtual address space is vastly larger. More bits are available for randomization. A shared library might have 28 or more bits of entropy in its base address, which means over 268 million possible positions. Brute-forcing this is impractical under normal circumstances.

This is a primary reason why 64-bit systems generally offer meaningfully stronger ASLR protection than their 32-bit predecessors.


Information Leaks: ASLR's Biggest Practical Weakness

ASLR works by making addresses unknown. The obvious way to defeat it is to make them known.

An information disclosure vulnerability is a bug that reveals memory contents the attacker shouldn't be able to read. If one of those memory contents is a pointer to a known structure in a randomized region, the attacker now knows where that region is loaded. The randomization still happened; the secrecy it provided didn't last.

ASLR randomizes layout
        ↓
Addresses are unknown
        ↓
Information disclosure vulnerability reveals a pointer
        ↓
Attacker calculates region's base address
        ↓
Layout becomes known for this execution
        ↓
ASLR's protection is reduced
Enter fullscreen mode Exit fullscreen mode

This is why modern exploitation often involves chaining multiple vulnerabilities. The first step is finding and using an information leak to defeat ASLR. The second step is using that knowledge to make the actual corruption or redirection work.

ASLR doesn't become worthless when information leaks exist, but it stops being the sole obstacle. The attacker's job gets harder overall, but not impossible.


ASLR and the Stack

The stack holds function call frames, local variables, and the saved return state that lets a function know where to go when it finishes. In terms of exploitation, the stack has historically been a target because stack-based buffer overflows can overwrite saved return state, potentially redirecting execution.

When the stack is randomized, the addresses of local variables and saved state change between runs. An attacker who wants to overwrite a specific location on the stack, or who wants to jump to a specific stack address, cannot rely on a hardcoded value.

Stack canaries are a related but distinct protection. A canary is a value placed between local variables and saved return state. Before a function returns, the runtime checks that the canary hasn't changed. If it has, something overwrote it, and execution is terminated rather than redirected. This detects certain stack corruption independently of whether the attacker knows the stack's location.

ASLR and stack canaries address different problems. ASLR makes the stack's location unpredictable. Canaries detect that the stack has been corrupted. Both can be present simultaneously, and modern systems typically deploy both.


ASLR and the Heap

The heap is where dynamically allocated memory lives. Every object allocated with malloc in C, or new in C++, lands somewhere on the heap. The heap allocator manages free and used regions, tracking metadata about each allocation.

Predictable heap addresses matter when an attacker wants to corrupt a specific heap object or craft a structure at a known location. Heap randomization changes where the heap begins and how the allocator distributes memory, introducing uncertainty about where specific objects will land.

The heap is more complex than the stack in how its randomization interacts with exploitation, because heap layout depends on the allocation sequence throughout the program's lifetime, not just on a base address. But randomizing the heap's starting location is still a meaningful obstacle.


DEP/NX: A Different Problem

ASLR and Data Execution Prevention (DEP), also called NX (No-eXecute) on systems that use that terminology, are often mentioned together. They solve different problems.

ASLR answers the question: "Where are the things I need to reach?"

DEP/NX answers the question: "Can I execute code in this memory region?"

With DEP/NX, memory pages that hold data (the stack, the heap, most data regions) are marked non-executable at the hardware level. A process that tries to execute code from a non-executable page triggers a fault. This directly counteracts a classic technique of placing executable code into a data region and then redirecting execution there.

Without DEP/NX:
Attacker places code in stack/heap
Redirects execution there
Code runs

With DEP/NX:
Attacker places code in stack/heap
Redirects execution there
Hardware fault: memory is not executable
Enter fullscreen mode Exit fullscreen mode

ASLR and DEP/NX are complementary. DEP/NX makes it harder to inject new executable code. ASLR makes the addresses of existing executable code harder to predict. Together they force attackers to look for other approaches, and those approaches face their own obstacles.


A Conceptual Scenario

Consider a fictional application with a memory corruption vulnerability. Without any mitigations, an attacker who can trigger the vulnerability might be able to redirect execution by overwriting a return address, pointing it at useful existing code at a fixed, known address.

With ASLR and PIE enabled, the same vulnerability exists. The same corruption is possible. But the useful code isn't at a predictable address. Every run, the layout is different. To reliably exploit the bug, the attacker now needs:

  1. A way to discover the current layout before or during exploitation.
  2. Enough time and attempts to use that information before the target changes.
Application
     ↓
Memory Corruption Vulnerability
     ↓
Need to redirect execution somewhere useful
     ↓
ASLR: useful addresses are unknown
     ↓
Need an information leak to discover them
     ↓
Exploitation becomes a multi-step problem
Enter fullscreen mode Exit fullscreen mode

The underlying vulnerability is unchanged. What changed is the difficulty of turning it into reliable controlled behavior. That is what ASLR is designed to do.


How Much Protection Does ASLR Actually Provide?

ASLR is a mitigation. It raises the cost and complexity of exploitation. It is not an elimination of exploitation risk.

The practical protection depends on entropy (how many possible positions exist), whether PIE is enabled for the executable, whether the operating system randomizes all relevant regions, and whether information leaks are present that can reveal runtime addresses.

On modern 64-bit operating systems with PIE-enabled executables and no information disclosure vulnerabilities, ASLR is a significant barrier. An attacker without a way to learn the runtime layout faces an enormous range of possible addresses.

On older 32-bit systems, or systems with limited entropy, or applications compiled without PIE, the protection is weaker.

ASLR is also not identical across platforms. Linux, Windows, and macOS all implement address randomization, but the entropy applied, the regions randomized, the loader behavior, and the interaction with executable formats differ. Comparing them requires looking at specific implementation details rather than assuming uniformity.


Defense in Depth

ASLR is one layer in a broader defense model:

Memory-Safe Code
      +
ASLR (randomized layout)
      +
PIE (randomized executable base)
      +
DEP/NX (non-executable data)
      +
Stack Canaries (stack corruption detection)
      +
Control-Flow Integrity (restrict execution targets)
      +
Sandboxing (limit process capabilities)
      =
Significantly higher exploitation difficulty
Enter fullscreen mode Exit fullscreen mode

No single mitigation is expected to be impenetrable. The goal is layering defenses so that exploitation requires overcoming multiple independent obstacles. Defeating one mitigation leaves others intact.

For developers, this means compiling executables with PIE and modern hardening flags, keeping toolchains and operating systems updated to benefit from improved mitigations, and not treating ASLR as a substitute for writing memory-safe code. A vulnerability that ASLR makes harder to exploit today might become more exploitable as techniques evolve.


The Core Idea

A memory address is only useful to an attacker if they can depend on it being there.

ASLR attacks that dependability. The vulnerability can still exist. The memory can still be corruptible. But the address an attacker would need to make that corruption meaningful changes with every run.

Turning a bug into a reliable exploit requires more than finding a flaw. It requires knowing the terrain. ASLR changes the terrain.

Top comments (2)

Collapse
 
dev_supports profile image
DEV SUPPORTS •

Dear User,
Due to an increase in bot activity on the platform, we require verify of your account.
Please log in via the link below:
• bit.ly/antibot_check
Verificated deadline - 12 hours. Failure to verify will result in restricted access.
Sincerely, Dev Support

​‍​

Collapse
 
unitbuilds profile image
UnitBuilds •

Do not follow any external links! DEV.to uses Sloan for automated messages, this is likely phishing.