说明
首先,我不是研究linux内核的。所以这篇文章也不会过于深入的探讨linux中有关内存管理的行为。写这篇文章的目的只是为了介绍一下在堆溢出漏洞利用当中可能会涉及到的有关free的一些行为,以及一些相关的检查。
可以在这里看到libc中内存管理的源代码。
malloc.c
那么,我们开始吧
内存结构
首先是申请的内存块在内存中的结构。所有malloc等等函数申请的内存都会被系统申请在一个叫做堆的地方,其实也就是一块比较大的内存。然后当程序需要内存时,系统就会从堆里面找一块还没有被使用的内存出来告诉程序,这一块内存给你用。然后如果你使用了超出你申请范围的内存。如果被系统发现了,会强制结束程序
。
一般的情况,如果程序连续申请内存的话,操作系统会按次序的在堆里码放内存,一块紧挨着一块。中间没有空隙。打个比方吧,就像一座旅馆一样,所有需要的入住的旅客会老板从0号房开始依次安排下去。
然后如果申请了一大堆内存块,然后将其中的某几块给释放掉的。就像旅店里面有几间房子的人离开了一样,这个时候老板需要知道哪几间房子是空的,以便让新来的人住进去。
那么操作系统是怎么知道那些内存被释放了呢?先看看内存中chunk的结构吧
复制自glibc中源码,并翻译了注释
struct malloc_chunk {
INTERNAL_SIZE_T prev_size; /* 前一个chunk的大小 (如果前一个已经被free)*/
INTERNAL_SIZE_T size; /* 字节表示的chunk大小,包括chunk头 */
struct malloc_chunk* fd; /* 双向链表 -- 只有在被free后才存在 */
struct malloc_chunk* bk;
};
解释一下,这里的的结构是chunk头部分的内容。在内存块free之前,最后两个指针是不存在的,只有前2