Systems Security & Exploitation

return-oriented programming

/ R-O-P /

Suppose someone forbids you from writing new ransom notes, but you are allowed to cut words out of existing newspapers and glue them together. You can still spell out any message — you just reuse text that is already there. Return-oriented programming (ROP) is that idea applied to code: when an attacker cannot inject and run their own machine code (because data pages are non-executable), they instead stitch together tiny snippets of the program's EXISTING, already-executable code to perform arbitrary computation.

It works because DEP/NX made injected shellcode unrunnable, so attackers turned to code reuse. The building blocks are gadgets: short sequences of existing instructions that end in a ret, such as 'pop rdi; ret' (which loads a value into rdi then returns) or 'pop rax; ret'. The attacker, having hijacked the stack via an overflow, fills it not with one return address but with a whole ROP chain: a sequence of gadget addresses interleaved with the data those gadgets consume. Each gadget's ending ret pops the NEXT gadget address off the attacker-controlled stack and jumps to it. So the stack itself becomes the program, and ret is the 'next instruction' engine. By choosing the right gadgets, the attacker can load registers, do arithmetic, and ultimately call a real function like execve or mark a page executable — all using only bytes that were already in the binary and its libraries.

It matters because ROP is the technique that made DEP alone insufficient, and it remains the backbone of modern memory exploitation. The honest framing: ROP needs to KNOW the addresses of its gadgets, so it is gated by ASLR — which is why an information leak (an arbitrary read) is usually a prerequisite. The defenses aimed squarely at ROP are Control-Flow Integrity (an indirect ret/call must land on a sanctioned target) and shadow stacks (a return must match the real call), which break the chain even when the bug fires.

// a ROP chain laid out on the hijacked stack (low -> high addresses): [ addr of 'pop rdi; ret' ][ 0x... "/bin/sh" ][ addr of system() ] // gadget pops the string pointer into rdi, then ret jumps into system()

Each ret hands control to the next address on the stack — the stack becomes a program written in gadgets.

ROP needs gadget addresses, so it is usually paired with an info leak to beat ASLR; jump-oriented programming (JOP) is the sibling that chains indirect jumps instead of returns, useful where ret-based gadgets are constrained.

Also called
ROPcode-reuse attackcode reuse返回導向程式碼重用攻擊