参考hac师傅的博客和CTF-wiki自己总结一下。理解有误,请多指正。
堆块概念
堆为程序运行时可以由程序动态申请的线性内存区域,由低地址向高地址增长(栈为从高到低),在C语言中可以通过malloc
和free
进行堆块申请和释放操作。
堆块机制
堆分配中以chunk为单位,其中chunk的数据结构如下:
struct malloc_chunk {
INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if free. */
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
struct malloc_chunk* bk_nextsize;
};
prev_size
:当前一个堆块为free
状态时,存放前一个堆块的大小。在前一个堆块不处于空闲状态时,数据为前一个堆块中用户写入的数据,本字段不计入chunk的大小计算。
size
:本堆块的大小,计算方法为size字段(32位为4|64位为8)+用户申请的大小+对齐
,32位下对8对齐,64位下对16对齐。且chunk地址的偏移为相邻上一个chunk的地址+上一个chunk的size。在pwndbg中调试好像会加上一位PREV_INUSE。
fb&bk
:当chunk为free
的状态时,分别指向chunk所在单向链表中的前一个chunk和后一个chunk。在被分配状态时,均用来存储数据,fb
为存储数据的开始位置。
fb_nextsize&bk_nextsize
:在被分配状态时也用来存储数据,在free
状态时只在large bin中用到,目前没有用,等用到了再总结。
堆块分配机制
Bins
A bin is a list (doubly or singly linked list) of free (non-allocated) chunks.
bin为一个单向或者双向链表存放空闲的chunk,下一次分配时,若bin中有大小合适的chunk会直接分配出去。bin由存放其中的chunk大小分类为fastbin
、smallbin
、largebin
。
比较常用的是fastbin,在32位系统下fastbin主要存储0-80字节的chunk,在64位系统下存储0-160字节的chunk。
其中还有一个unsorted bin
,是当small chunk
或large chunk
free掉之后,不会直接进入smallbin或largebin,而是会先进入unsortedbin
arena
个人理解arena为chunk的存储组织形式,在arena的最上层始终为Top chunk,向下分出用户chunk,其中主线程中的arena为main arena。
top chunk
top chunk为arena的边界,当bin中无合适的chunk分配时,会将top chunk分出一部分进行分配。
当与top chunk相邻的chunk处于free状态时,该chunk不会进入bin中,而是会合并入top chunk。