堆基础
笔记取自于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的状态,及相应堆块大小的通常使用频度,进行分配:
- fast bin(大小相同)
- small bin(大小相同)
- unsorted bin(大小相同)
- large bin(最小满足)
- bins(最小满足)
- top chunk(大小相同)
- 系统函数分配
ptmalloc响应用户内存回收
free将用户暂时不用的chunk回收给堆管理器,在合适的条件下会返还给操作系统
- 判断是否是mmaped chunk,若是直接解出映射
- fast bin或者tcache bin
- 在条件满足时,会与物理相邻的chunk合并,按大小分别放入small bin及large bin
常用命令记录
heap
bins
x/40gx
x/40wx