> 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/17.-understanding-heap.md).

# 0x16 — Understanding Heap: Malloc, Free, and Tcache

## Overview

The **heap** is a dynamic memory region managed by `malloc`, `free`, and related functions. Understanding how the heap allocator works internally is essential for exploiting heap vulnerabilities like Use-After-Free, Double Free, and Heap Overflow.

This guide focuses on **glibc's ptmalloc2** allocator, specifically the **tcache** (thread cache) introduced in glibc 2.26.

***

## Memory Regions

| Region | Size        | Purpose                          |
| ------ | ----------- | -------------------------------- |
| Stack  | Fixed/small | Local variables, function frames |
| Heap   | Dynamic     | `malloc`/`free` managed memory   |
| BSS    | Fixed       | Uninitialized global variables   |
| Data   | Fixed       | Initialized global variables     |

The heap grows **upward** (toward higher addresses). `brk()` and `mmap()` expand it.

***

## Chunk Structure

Every allocated or freed region on the heap is a **chunk**. Each chunk has a header:

```
+---------------------------+
| prev_size (8 bytes)       |  ← size of previous chunk if prev is free
+---------------------------+
| size      (8 bytes)       |  ← size of this chunk | flags
+---------------------------+  ← user pointer (returned by malloc) starts here
| user data                 |
| ...                       |
+---------------------------+
```

### Flags in the `size` field (lowest 3 bits)

* **P (0x1)**: Previous chunk in use (PREV\_INUSE)
* **M (0x2)**: Chunk was mmap'd
* **A (0x4)**: Non-main arena

Actual size is `size & ~0x7` (mask out flags).

```c
// Example: size = 0x21 → actual size = 0x20, PREV_INUSE set
```

***

## How `malloc` Works

```c
void *ptr = malloc(size);
```

1. Rounds up `size` to nearest alignment (16 bytes on 64-bit)
2. Checks **tcache** for a matching free chunk → returns it immediately if found (fast path)
3. Checks **fastbins** → returns if found
4. Checks **smallbins**, **largebins**, **unsorted bin**
5. Calls `brk()` or `mmap()` to get more memory from OS if needed

***

## How `free` Works

```c
free(ptr);
```

1. Validates the chunk header
2. If size fits in **tcache** (< 0x408): places it in the tcache singly-linked list
3. Otherwise: consolidates with adjacent free chunks, places in appropriate bin

***

## Bins Overview

| Bin       | Chunk Size    | Structure          | Notes                  |
| --------- | ------------- | ------------------ | ---------------------- |
| Tcache    | ≤ 0x408 bytes | Singly-linked list | Per-thread, 7 max/size |
| Fastbins  | ≤ 0x80 bytes  | LIFO singly-linked | No coalescing          |
| Unsorted  | Any size      | Doubly-linked      | Temporary holding bin  |
| Smallbins | < 0x400 bytes | Doubly-linked FIFO | Sorted by size         |
| Largebins | ≥ 0x400 bytes | Doubly-linked      | Ranges of sizes        |

***

## Tcache (Thread Cache) — Deep Dive

Introduced in glibc 2.26. Each thread has a `tcache_perthread_struct` with:

* **64 bins** for sizes 0x20 to 0x410 (in 0x10 increments)
* **Each bin** holds up to **7 entries** (default)
* **LIFO** order (last freed = first returned by malloc)

### Tcache chunk freed structure:

```
+------------------+
| prev_size        |
+------------------+
| size             |
+------------------+  ← user data starts here (now free)
| fd (next ptr)    |  ← points to next chunk in tcache bin
+------------------+
| key              |  ← glibc 2.29+: contains heap address for double-free detection
+------------------+
```

### Tcache in memory:

```
tcache_perthread_struct {
    uint16_t counts[64];     ← how many entries in each bin
    tcache_entry *entries[64]; ← head pointers to each bin's linked list
}
```

***

## Visualizing malloc and free

```c
// Allocate three chunks
char *a = malloc(0x20);   // chunk A
char *b = malloc(0x20);   // chunk B
char *c = malloc(0x20);   // chunk C

// Free A and B
free(a);   // tcache bin[0x20]: A → NULL
free(b);   // tcache bin[0x20]: B → A → NULL

// Next malloc(0x20) returns B (LIFO)
char *d = malloc(0x20);   // d == b
// tcache bin[0x20]: A → NULL
```

***

## Heap in GDB (pwndbg)

```bash
gdb ./vuln
> heap          # show all heap chunks
> bins          # show all bin contents
> tcache        # show tcache state
> vis_heap_chunks  # visual heap layout
> malloc_chunk 0x602010   # inspect a specific chunk
```

***

## Simple Heap Demo (`demo.c`)

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

int main() {
    printf("malloc(0x20) returns: ");
    void *a = malloc(0x20);
    printf("%p\n", a);

    printf("malloc(0x20) returns: ");
    void *b = malloc(0x20);
    printf("%p\n", b);

    printf("Freeing a...\n");
    free(a);

    printf("malloc(0x20) returns: ");
    void *c = malloc(0x20);
    printf("%p\n", c);
    // c == a (same address, reused from tcache)

    return 0;
}
```

```bash
gcc -o demo demo.c
./demo
# malloc(0x20) returns: 0x602260
# malloc(0x20) returns: 0x602290
# Freeing a...
# malloc(0x20) returns: 0x602260  ← reused!
```

***

## Heap Exploitation Primitive

Most heap attacks exploit the **free list (tcache/fastbin) pointers** stored in freed chunks:

```
Freed chunk layout:
[ prev_size ][ size ][ fd pointer ][ key/bk ][ user data... ]
```

If an attacker can:

* **Write into a freed chunk** (Use-After-Free / Heap Overflow) → corrupt `fd`
* **Double-free** a chunk → insert the chunk into tcache twice

Then subsequent `malloc` calls can return an **arbitrary address** → write-what-where.

***

## Key Addresses & Structures

```bash
# Check glibc version (affects tcache details)
ldd ./vuln | grep libc
strings /lib/x86_64-linux-gnu/libc.so.6 | grep "GNU C"

# In GDB
p &main_arena      # main allocator arena
p tcache           # current thread's tcache
```

***

## Key Takeaways

* Heap chunks have a **header** (prev\_size + size) before the user data pointer
* **Tcache** is the fastest allocation path — a per-thread LIFO singly-linked list
* Freed tcache chunks store a **forward pointer** (`fd`) in their user data area
* All heap exploitation techniques ultimately manipulate these free list pointers
* Understanding chunk layout and bin structure is essential before studying UAF, Double Free, etc.

***

## Useful pwntools Heap Functions

```python
from pwn import *

elf = ELF('./vuln')

# Helper for pwntools heap analysis
p = process('./vuln')
gdb.attach(p, '''
    heap
    bins
    tcache
    continue
''')
```


---

# 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/17.-understanding-heap.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.
