堆基础

笔记取自于PolarCTF入门系列讲座——PWN篇堆基础

前置知识

chunk分为:mmap_chunk,top_chunk,alloc_chunk,free_chunk

prev_size的后三位为标记位,A标记是否不属于main_arena,M位标记是否是mmap申请的chunk,P标识前一个chunk是否处于释放状态

若标记为1,则正在使用;若标记为0,则处于释放状态

prev_size表示前一个chunk的大小,size表示当前chunk的大小

若当前chunk处于释放状态,则fd指向后一个空闲的chunk,bk指向前一个空闲的chunk

图中,从fd开始向下属于用户区域

32位chunk的最小大小为0x10,64位chunk的最小大小为0x20,至少需要包含prev_size,size,fd,bk

+------------------+          +-------------------------------+
|   chunk_header   |          | prev_size             |A|M|P| |
+------------------+          +-------------------------------+
                              | size                          |
+------------------+          +-------------------------------+
|    user_space    |          | fd                            |
+------------------+          +-------------------------------+
                              | bk                            |
                              +-------------------------------+
                              | fd_nextsize                   |
                              +-------------------------------+
                              | bk_nextsize                   |
                              +-------------------------------+
                              | ...                           |
                              +-------------------------------+

fast bin

首个对应大小的chunk保存在malloc_state结构体的fastbinY数组中

后续对应大小的chunk以单链表形式进行存储,由fd进行链接

fastbinY数组默认大小为7个,范围为0x20~0x80,其最大大小由global_max_fast控制

fast bin采取先进后出的规则

在32位系统下,fastbin管理的chunk大小范围是从16字节到64字节

在64位系统下,fastbin管理的chunk大小范围是从32字节到128字节

unsorted bin

unsorted bin只有一个,他是small bin和large bin的缓冲区

unsorted bin是双链表结构,采取先进先出的规则,只有一个数组

加入tcache机制前,unsorted bin用于回收超出fast bin大小的chunk

加入tcache后,unsorted bin用于回收超出tcache最大大小的chunk

若某一chunk申请的大小是8结尾,则会借用下一个chunk的prev_size

例如malloc(0x18)的chunk大小为0x18+0x10(头部)-0x8+1=0x21

small bin

small_bin中的chunk通过双链表进行链接,范围是0x20~0x400

small bin采取先进先出规则

单个small_bin链接大小相同的chunk

bins数组存储small bin链时:第一个small bin链中chunk的大小为32字节,后续每个small bin中chunk的大小依次增长两个字长(32位相差8字节,64位相差16字节)

large bin

large bin保存大于0x400大小的chunk

large bin链接方式比较特殊,fd指向前一个大小相同的chunk,bk指向后一个大小相同的chunk

fd_nextsize->比他小的最大chunk,bk_nextsize->比他大的最小的chunk

large bin分为6组,每组包含一个范围大小的chunk,第六组最大包含无限大的chunk

tcache bin

tcache是glibc-2.26之后新加入的机制,默认大小范围为0x20~0x400(高版本为0x410)

tcache是优先于fast bin的chunk缓冲区

通过next指针相连接,next指针指向fd的位置,也就是说tcache实际上用过fd形成的单链表进行链接

tcache默认大小为64个,每个链表最多链接7个,其余的将被放进unsorted bin或者fast bin中

前置知识

32位模式下它是一个4GB的内存地址块

用户栈都是向低地址增长

堆都是向高地址扩展

Random这些随机值目的是防止恶意程序,这是一种安全机制ASLR,主要防止缓冲区溢出攻击

+------------------------------------------------------------+
|                          Kernel space                      | 
|  User code CANNOT read from nor write to these addresses,  |
|          doing so results in a Segmentation Fault          |
+------------------------------------------------------------+0xc0000000==TASK_SIZE
|                                                            |Random stack offset
+------------------------------------------------------------+
|                             Stack                          |
|                          (grows down)                      |RLIMIT_STACK
|                               ↓                            |
+------------------------------------------------------------+
|                                                            |Random mmap offset
+------------------------------------------------------------+ 
|                     Memory Mapping Segment                 |
| File mappings (including dynamic libraries) and anonymous  |
| mappings. Example: /lib/libc.so                            |
|                               ↓                            |
+------------------------------------------------------------+
|                                                            |program break
+------------------------------------------------------------+brk
|                               ↑                            |
|                              Heap                          |
+------------------------------------------------------------+start_brk
|                                                            |Random brk offset
+------------------------------------------------------------+
|                           BSS segment                      |
|    Uninitialized static variables, filled with zeros.      |
|    Example: static char *userName;                         |
+------------------------------------------------------------+end_data
|                          Data segment                      |
|    Static variables initialized by the programmer.         |
|    Example: static char *gonzo = "God's own prototype";    |
+------------------------------------------------------------+start_data
|                         Text segment (ELF)                 |end_code
|  Stores the binary image of the process (e.g., /bin/gonzo) |
+------------------------------------------------------------+0x08048000
|                                                            |
+------------------------------------------------------------+0

ptmalloc响应用户内存分配

glibc根据申请堆块的大小,各个bin的状态,及相应堆块大小的通常使用频度,进行分配:

  1. fast bin(大小相同)
  2. small bin(大小相同)
  3. unsorted bin(大小相同)
  4. large bin(最小满足)
  5. bins(最小满足)
  6. top chunk(大小相同)
  7. 系统函数分配

ptmalloc响应用户内存回收

free将用户暂时不用的chunk回收给堆管理器,在合适的条件下会返还给操作系统

  1. 判断是否是mmaped chunk,若是直接解出映射
  2. fast bin或者tcache bin
  3. 在条件满足时,会与物理相邻的chunk合并,按大小分别放入small bin及large bin

常用命令记录

heap
bins
x/40gx
x/40wx