# Binary Exploitation Dtors Fini Array

> Exploit arbitrary write vulnerabilities using .dtors and .fini_array sections to execute shellcode at program exit. Use this skill whenever the user mentions binary exploitation, arbitrary write vulnerabilities, .dtors, .fini_array, destructor sections, or needs to execute code after main() returns. Also use when the user has write access to a binary's memory and wants to hijack program termination.

- Skill: `abelrguezr/binary-exploitation-dtors-fini-array` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/binary-exploitation-dtors-fini-array`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/binary-exploitation-dtors-fini-array/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/binary-exploitation-dtors-fini-array

---


# Binary Exploitation: .dtors & .fini_array Exploitation

This skill helps you exploit **arbitrary write vulnerabilities** by hijacking the `.dtors` and `.fini_array` sections to execute shellcode when a program terminates.

## When to Use This Technique

Use this approach when:
- You have an **arbitrary write vulnerability** (can write to any address)
- You need to **execute shellcode** but don't have a direct code execution primitive
- The binary has **writable .dtors or .fini_array sections** (check with `objdump` or `rabin2`)
- You want to execute code **after main() returns**

## Understanding the Sections

### .dtors Section

The `.dtors` section contains **destructor function addresses** that execute **before the program finishes** (after `main()` returns).

**Key points:**
- Addresses are stored in the `.dtors` section
- Overwrite `__DTOR_END__` with your shellcode address to execute it
- Look for markers between `0xffffffff` and `0x00000000`
- If you only see these markers, no functions are registered - overwrite the `0x00000000` entry

### .fini_array Section

The `.fini_array` section is similar to `.dtors` - it contains **function addresses called before program termination**.

**Key points:**
- Functions are called in **reverse order** (last entry first)
- Each entry executes **only once** (prevents eternal loops by default)
- Start writing from the **last entry** to control execution order
- With **Full RELRO** or newer **Partial RELRO**, this section is **read-only** (check first!)

## Step-by-Step Exploitation Flow

### Step 1: Inspect the Binary

First, check if the binary has exploitable sections:

```bash
# Check .dtors section
objdump -s -j .dtors ./binary
rabin2 -s ./binary | grep "__DTOR"

# Check .fini_array section
objdump -s -j .fini_array ./binary
rabin2 -s ./binary | grep "__fini"
```

**What to look for:**
- `.dtors`: Values between `0xffffffff` and `0x00000000` (the `0x00000000` is writable)
- `.fini_array`: Function addresses you can overwrite
- **RELRO status**: Check if sections are read-only (not exploitable if they are)

### Step 2: Find a Shellcode Location

You need a **writable and executable** location for your shellcode:

```bash
# Check memory layout
readelf -l ./binary | grep -A 5 "GNU_STACK"

# Look for writable sections
objdump -h ./binary | grep -E "(writable|RW)"

# Common locations:
# - .data section
# - .bss section  
# - Heap (if you can control it)
# - Environment variables (if NX is disabled)
```

### Step 3: Craft the Exploit

**For .dtors:**
1. Find the address of `__DTOR_END__` (the `0x00000000` marker)
2. Place your shellcode in a writable/executable location
3. Use the arbitrary write vulnerability to overwrite `__DTOR_END__` with your shellcode address
4. When the program exits, your shellcode executes

**For .fini_array:**
1. Find the address of the last entry in `.fini_array`
2. Place your shellcode in a writable/executable location
3. Use the arbitrary write vulnerability to overwrite the entry with your shellcode address
4. When the program exits, your shellcode executes

### Step 4: Handle RELRO Protections

**Check RELRO status:**
```bash
readelf -l ./binary | grep -i relro
```

**If Full RELRO or Partial RELRO:**
- `.fini_array` is likely **read-only** - this technique won't work
- Consider alternative techniques:
  - Return-oriented programming (ROP)
  - Format string vulnerabilities
  - Other memory corruption primitives

## Eternal Loop Technique (Advanced)

If you have **at least 2 entries in .fini_array**, you can create an eternal loop:

1. **First write**: Call the vulnerable arbitrary write function again
2. **Second write**: Calculate the return address stored by `__libc_csu_fini` (the function calling `.fini_array` functions) and overwrite it with `__libc_csu_fini`'s address
3. This makes `__libc_csu_fini` call itself again, executing `.fini_array` functions repeatedly
4. You get multiple arbitrary writes to chain exploits

**Reference**: See [guyinatuxedo's insomnihack18 writeup](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html) for a detailed example.

## Common Pitfalls

1. **Shellcode location**: Make sure your shellcode is in a **writable AND executable** location
2. **RELRO**: Check if sections are read-only before attempting
3. **Entry order**: `.fini_array` entries execute in **reverse order**
4. **Single execution**: Each `.fini_array` entry executes only once (unless you use the eternal loop technique)
5. **Address calculation**: Ensure you're writing to the correct address (the section address, not the function address)

## Example Exploit Structure

```python
from pwn import *

# Connect to target
p = process('./binary')

# Find addresses
binary = ELF('./binary')
dtors_end = binary.symbols['__DTOR_END__']
fini_array = binary.section('.fini_array').address

# Prepare shellcode
shellcode = asm(shellcraft.sh())

# Find writable location (example: .data section)
data_addr = binary.section('.data').address

# Write shellcode to memory
p.send(shellcode)

# Overwrite .dtors or .fini_array with shellcode address
# This depends on your arbitrary write vulnerability
# Example: write to dtors_end
exploit_payload = p64(shellcode_addr)
p.sendline(exploit_payload)

# Wait for program to exit and shellcode to execute
p.interactive()
```

## Debugging Tips

```bash
# GDB debugging
gdb ./binary
(gdb) break main
(gdb) continue
(gdb) info sections | grep -E "(dtors|fini)"
(gdb) x/20wx __DTOR_END__
(gdb) x/20wx __fini_array_end__

# Check if sections are writable
(gdb) info proc mappings
```

## When NOT to Use This Technique

- Binary has **Full RELRO** or **Partial RELRO** with read-only `.fini_array`
- No **arbitrary write vulnerability** available
- **NX/DEP** is enabled and you can't find a writable+executable location
- You need **immediate execution** (this technique only works at program exit)

## Related Techniques

- **ROP chains**: When you can't write shellcode but can chain existing code
- **Format string exploits**: When you have format string vulnerabilities
- **Heap exploitation**: When you have heap corruption primitives
- **Return address overwrites**: Classic stack buffer overflow technique

