pwn之堆入门

pwn之堆入门(基础知识)

在程序执行的过程中,由malloc申请的内存空间被称作chunk,而当程序申请的chunk被free时会被加入到相应的空闲管理列表(bin)中。

Chunk结构:

pwn之堆入门_第1张图片

解释:

pre_size:

前一个chunk块的大小,如果chunk_size的P位为1则pre_size无效,上个chunk可以使用pre_size的空间。(前一个chunk块的大小,指的是低地址的chunk)

chunk_size:

当前chunk的大小,由于chunk是8字节对齐的,所以后3位分别为,A(是否为main_arena,即主线程)、M(该chunk是否由mmap分配),P(前一个chunk是否被分配,故经常会看到chunk_size比chunk大1字节)。

mem:

用户申请的空间,即malloc 申请得到的内存指针,其实指向 mem 的起始处。chunk 处于分配状态时,从 fd 字段开始是用户的数据。chunk 空闲时,会被添加到对应的空闲管理链表中,其字段的含义如下
fd 指向下一个(非物理相邻)空闲的 chunk
bk 指向上一个(非物理相邻)空闲的 chunk
通过 fd 和 bk 可以将空闲的 chunk 块加入到空闲的 chunk 块链表进行统一管理

大小:

Chunk的大小必须是 2 * SIZE_SZ 的整数倍。如果申请的内存大小不是
2 * SIZE_SZ 的整数倍,会被转换满足大小的最小的 2 * SIZE_SZ 的倍数。SIZE_SZ 是 4;64 位系统中,SIZE_SZ 是 8。

故在32位中最小的chunk(min_size)的大小为:8+4+4=16字节,其中8字节为用户使用的空间,4字节为pre_size,4字节为chunk_size

64位为:16+8+8=32字,16字节为用户使用的空间,8字节为pre_size,8字节为chunk_size(最小的chunk意味着只要用户申请的size小于min_size,得到的空间都为min_size)

空闲管理列表(bin):

用户释放掉的 chunk 不会马上归还给系统,ptmalloc会统一管理 heap 和 mmap 映射区域中的空闲的chunk。在具体的实现中,ptmalloc 采用分箱式方法对空闲的chunk 进行管理。首先,它会根据空闲的 chunk 的大小以及使用状态将 chunk 初步分为4类:fast bins,small bins,large bins,unsorted bin。每类中仍然有更细的划分,相似大小的 chunk 会用双向链表链接起来。也就是说,在每类 bin 的内部仍然会有多个互不相关的链表来保存不同大小的chunk。在这里我们主要学习的两种bin:fastbins和unsorted bin。

fastbins:

glibc以单链表结构对其进行管理,且每个bin采取的是LIFO(后进先出,跟栈类似)的策略,即最近释放的chunk会被优先分配,同时fastbin中的chunk的P位设为1,不会进行合并操作。

fastbin大小(注:以下的大小都为mem的大小,实际chunk的空间还要加上chunk_head(64位为16字节,32位为8字节))

fastbins中最多有10个bin:
pwn之堆入门_第2张图片

Unsorted bins:

如果free的chunk块不在fastbins范围内,就会被乱序存放在unsorted bins内,即是未排序的bin,而Unsortedbins的作用是视作空闲 chunk 回归其所属(larg/small) bin 之前的缓冲区。当用户申请(malloc)一个大于fastbin的chunk时,首先会遍历unsorted bin中的chunk,找到合适的chunk,这时再将其他不满足的chunk保存到small bin和large bin中也是顺便的事情,所以从unsorted bin命名也可看成,这是一个未排序的bin,需要排序就需要遍历,遍历后的chunk就直接分类到(larg/small)bin中。

Unsortedbin在使用过程中采用的遍历顺序是FIFO,同时bin中的chunk是以双向链表连接的,fd指向先入bin的chunk,bk指向后入bin的chunk

参考文章:
从一个linux堆分配例子中理解4种bins
九层台的”PWN学习整理“
CTF-wiki 堆相关数据结构

你可能感兴趣的:(攻防世界)