All write-ups
25 min read

The Ultimate Guide to Binary Exploitation

PwnBinary ExploitationROPAssembly

The Ultimate Guide to Binary Exploitation: Theoretical Mechanics and Defensive Mitigations

Welcome to the definitive study guide for software security and binary exploitation. This document synthesizes key theoretical concepts spanning system architecture, memory corruption vulnerabilities, and the modern defensive mitigations designed to thwart them. This guide is strictly educational, focusing on the mechanics of exploitation and defense to foster a deeper understanding of secure software development.


1. Program Compilation and Anatomy

Before analyzing vulnerabilities, it is essential to understand how source code becomes an executable binary and how it resides in memory.

1.1 The Compilation Pipeline

The transformation of a C program into a machine-readable executable involves four distinct phases:

  1. Preprocessing: Interprets preprocessor directives (e.g., #include, #define). Macros are expanded, and headers are included.
  2. Compilation: Translates the preprocessed source code into assembly language specific to the target architecture.
  3. Assembly: Converts the assembly instructions into machine code, producing an object file (.o).
  4. Linking: Combines multiple object files and links external libraries to create a single cohesive executable.

Programs can be linked statically (self-contained, no external dependencies) or dynamically (libraries are loaded externally at runtime).

1.2 The ELF Format

On Linux systems, the standard binary format is ELF (Executable and Linkable Format). It contains several critical sections necessary for linking and execution:

1.3 Memory Layout

When an OS loads an executable, it maps it into a virtual memory space divided into segments:


2. Architecture and The Stack

2.1 x86 Registers and Calling Conventions

In x86 (32-bit) architecture, operations are performed using registers like EAX (accumulator), ECX (counter), ESP (Stack Pointer), and EBP (Base Pointer).

When functions are called, arguments and return values must be passed according to a calling convention.

2.2 Stack Frames

Every function call creates a Stack Frame (or Activation Record) on the stack. A typical x86 stack frame contains:

  1. Function arguments.
  2. The Return Address (the instruction to execute after the function finishes).
  3. The saved Base Pointer (previous stack frame's EBP).
  4. Local variables.

3. Memory Corruption Vulnerabilities

Memory corruption occurs when a program inadvertently modifies unintended memory locations. This typically stems from unsafe memory handling functions in C (e.g., strcpy, gets, scanf).

3.1 Buffer Overflows

A buffer overflow happens when data written to a buffer exceeds its allocated boundaries. If a local buffer on the stack is overflowed, the excess data will overwrite adjacent memory.

void vulnerable_function(char *input) {
    char buffer[20];
    // strcpy does not check bounds, leading to potential overflow
    strcpy(buffer, input); 
}

Theoretical Exploitation: Because the buffer is located below the saved Return Address on the stack (stacks typically grow downwards in memory, while buffers are written upwards), an attacker can supply an oversized input that writes past buffer, overwriting the Return Address. When the function finishes and executes the RET instruction, the CPU will jump to the attacker-controlled address instead of the legitimate caller.

3.2 Code Injection and Shellcoding

In traditional buffer overflows (assuming no mitigations), an attacker could overwrite the Return Address with a pointer to their own input. This input would contain Shellcode—a specialized payload written in raw assembly instructions (often designed to execute /bin/sh).

3.3 Format String Vulnerabilities

Functions like printf rely on format specifiers (e.g., %s, %x) to process arguments. If user input is passed directly to the formatting function without a format string, the program will misinterpret the input as format specifiers.

// Vulnerable
printf(user_input);

// Secure
printf("%s", user_input);

Theoretical Mechanics:


4. Modern Defensive Mitigations & Bypasses

As exploitation techniques evolved, operating systems and compilers introduced security mitigations to break deterministic exploitation.

4.1 Non-Executable Stack (NX / DEP)

4.2 Return-Oriented Programming (ROP)

4.3 Stack Canaries

4.4 Address Space Layout Randomization (ASLR)

4.5 Control-Flow Integrity (CFI)


This guide serves as a foundational overview of the cat-and-mouse game between memory corruption vulnerabilities and modern defensive architectures. Secure coding practices and robust mitigations are the primary defense against these historical and ongoing threats.