Heap Exploitation - ianchen0119/About-Security GitHub Wiki
在本頁提到的 Heap 與資料結構的 Heap 不同,這邊的 Heap 是指可供作業系統與 Process 分配的記憶體空間,我們都知道, Stack 會存放已經初始化的固定長度資料,比起 Stack , Heap 有了更多彈性,我們想要使用多少空間就分配多少空間,並且在使用後可以進行記憶體回收避免浪費。
#include <stdlib.h>
int *p = (int*) malloc(sizeof(int));
// ...
free(p);
上面的 C 語言範例便是使用 malloc()
進行動態記憶體的配置,並且在使用完畢後呼叫 free()
對記憶體進行回收。
觀察上圖,我們可以知道 Heap 是由底部往上分配的,與 Stack 恰恰相反。
在 Linux 中,由 memory allocator 由 glibc 實作,更多資訊如下:
- dlmalloc -- General purpose allocator
- ptmalloc2 -- glibc
- jemalloc -- Firefox
- tcmalloc -- chrome
- 第一次呼叫
malloc()
size >= 128 KB
+--------+ -----> +--------+ -----> +------------+
| malloc | | mmap | | sys_mmap |
+--------+ +--------+ +------------+
|
| trap to kernel
| size < 128 KB
+ -----> +-------+ -----> +-----------+
| brk | | sys_brk |
+-------+ +-----------+
當我們第一次呼叫 malloc()
且要求的大小小於 128 KB 時, sys_brk()
都會分配 132 KB 的 Heap 段落,該段落稱為 main arena 。
這時,如果我們在程式中再次呼叫 malloc()
,只要已分配出去的大小不多於 128 KB ,都不會再執行系統呼叫向作業系統要求更多空間。
補充: 一旦作業系統分配給 Process 這段空間 (main arena) ,即使在程式執行中呼叫
free()
釋放了這些空間,也不會立刻返回給作業系統,而是由 glibc 代為保管。
使用 malloc()
分配的空間就是一個 Chunk , Chunk 主要由兩個區段組成:
- Chunk header
- prev_size
- size
- user data
此外,這些可用的 Chunk 會由鏈結串列管理,該鏈結串列的 Head 稱為 bin
。
Chunk 會以大小進行分類,不同種類的 Chunk 會由個別的 bin 進行管理,像是:
- fastbin (size <= 64B)
- smallbin (size <= 512B)
- largebin (size <= 128KB)
- unsortedbin
至於 Chunk 主要有三類:
- Allocated Chunk
- prev_size Chunk 基本上會放在一大段的連續記憶體中,如果該 Chunk 的上一段(實際記憶體的上一塊) Chunk 為 free chunk , prev_size 會存放上一塊 chunk 的大小。
- size
size 會存放該 Chunk 的大小,其中還包含了三個 flag:
- PREV_INUSE (bit 0) -- 紀錄上一塊 Chunk 是否被使用 。
- IS_MMAPPED (bit 1) -- 紀錄該 Chunk 是否由 mmap 分配。
- NON_MAIN_ARENA (bit 2) -- 是否不屬於 main arena 。
- Free Chunk
- prev_size
- size
- fd (pointer to next chunk)
- bk (pointer to last chunk)
- Top Chunk
前面提到了,在第一次呼叫
malloc()
且要求的大小小於 128 KB 時,sys_brk()
都會分配 132 KB 的空間,這時實際上用到的即為 Allocated Chunk ,剩下的皆是 Top Chunk 。 之後再呼叫malloc()
的話,只要大小足夠,都會從 Top Chunk 切割空間。
我們都知道,不同的 Chunk 會由不同的 bin 管理,當呼叫 malloc 與 free 時,管理 Free chunk 的 bin 會有以下變化:
- 原本的狀態:
+--------+ -----> +--------+ -----> +--------+
bin | | | | | |
+--------+ <----- +--------+ <----- +--------+
- 呼叫
malloc()
:
+--------------------------+
| |
| V
+--------+ - x -> +--------+ - x -> +--------+
| | | malloc | | |
+--------+ <- x - +--------+ <- x - +--------+
^ |
| |
+--------------------------+
- 呼叫
free()
:
+----------- X ------------+
| |
| V
+--------+ -----> +--------+ -----> +--------+
| | | free | | |
+--------+ <----- +--------+ <----- +--------+
^ |
| |
+----------- X ------------+