1. The Problem: NX Killed Shellcode
Before NX (mid-2000s), buffer overflow exploits worked by writing CPU instructions ("shellcode") into the buffer, then redirecting RIP to that shellcode. NX killed this. Now what?
2. What's a "Gadget"?
A gadget is a tiny snippet of code (1 to about 5 instructions) ending in ret, that exists somewhere in legitimate executable memory. libc has thousands of them. Your binary has hundreds. The attacker scans for them with tools like ROPgadget or Ropper.
3. The Chain: Stack-as-Program
The key insight: when a function executes ret, it pops the next 8 bytes off the stack into RIP and jumps there. If those 8 bytes are the address of another gadget that also ends in ret, the gadgets chain automatically.
4. A Real 3-Gadget Chain: Call system("/bin/sh")
The classic. The goal is to call system("/bin/sh") from libc to get a shell. system\'s first argument has to be in RDI (System V x86_64 ABI). We need a gadget that puts our string\'s address into RDI, then a way to jump into system. Step through it.
5. ASLR: What (Mostly) Stops This
ROP needs the attacker to know exact addresses of gadgets. ASLR randomizes those addresses every time the program (and libc) loads. Without the addresses, the chain can\'t be built. This is the modern defense, and it works, until the attacker finds an "info leak".