pwn系列之堆基础(五)

首先我们要了解一下堆的结构,堆其实也可看做一个结构体,里面有许多的元素,我们也称他为chunk。和栈不相同,栈是从高地址向低地址生长,可是堆却是从低地址向高地址生长,所以在我们所说的前一个chunk往往指低地址的chunk,后一个chunk往往指高地址的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;
};

接下来让我们来看看这里面的元素的含义
1、prev_size:如果该chunk的物理相邻的前一个chunk是空闲的,那就用来记录前一个chunk的大小,否则的话用来储存前一个chunk的数据,这也就是prev_size的复用。
2、size:用来记录该chunk的大小,这个大小必须是2*SIZE_SZ的倍数。在x86中,SIZE_SZ是4,在x64中SIZE_SZ是8。这也就说明该字段的低三个比特位一定是0,所以我们可以把它们利用起来,三个比特位从高到低表示AMP。
A:NON_MAIN_ARENA,记录当前的chunk是否不属于主线程,1表示不属于,0表示属于
M:IS_MAPPED记录当前chunk是否是由mmap分配的
P:PREV_INUSE,记录前一个chunk是否被分配,一般来说堆中的第一个被分配的chunk的size字段的P位都会是1,防止对前面的内存非法访问。当一个chunk的size的P位为0的时候,也就意味着前一个chunk空闲,也就是说当前chunk可以和前一个chunk合并
3、fd,bk,chunk处于分配状态的时候,从fd字段开始都是用户的数据,当chunk空闲的时候,会被添加到相对应的bins中,bins的话其实就是一个链表,有的是双向链表,有的是单向链表,既然是链表那就一定要有指针,这个就是指针,fd是指向前一个chunk的指针,bk是指向后一个chunk的指针
4、fd_nextsize,bk_nextsize,fd_nextsize表示前一个chunk的大小,bk_nextsize表示后一个chunk的大小,当然这个也是chunk空闲的时候采用,不过只有较大的chunk才会用到,也就是large chunk(一个bins的名称)。

我们看看我们申请了一个大小0x10的chunk,可是它的size却是33,我们来分析一下,他是第一个被分配的chunk,所以P位是1,那么剩下的32也就是0x20,我们申请的大小是0x10,剩下的0x10是什么呢,也就是我们的prev_size和size,这两个变量一个大小为0x8,刚好就是0x10了。然后我们还看到了还有一个很大的chunk,其实是堆控制器向内核申请了一个极大的chunk,然后我们申请的chunk从这个极大的chunk分割而来,或者是之前释放到bins的chunk得来。我们再来看看物理空间的分布

可以看到我们申请的0x10大小的堆实际占的空间是0x20多的0x10就是0x602000这个位置上的,而后面的0x602010才是我们可以编辑的0x10大小的空间
我们再看看释放后的,我总共申请了一个0x10、一个0x18和一个0x20,然后将三个全部释放

我们看到了除了一个大的chunk还有三个chunk,我们发现申请0x10和0x18最后的size都是0x20,这也就是之前说到的复用

我们可以看到三个chunk只有一个chunk的fd有值这是怎么回事呢,这就涉及到了bins的管理,一开始都是fastbin,所以我从fastbin开始

我们看到了,fastbins分成了0x20、0x30、0x40、0x50、0x60、0x70、0x80,不同的版本可能类别个数有差别,具体可以调试的时候看看,我们以0x20为例子,就是当我们chunk的size为0x20释放,那么这个chunk就会连接到这个位置的bins后面,可以理解为这个fastbin在图片中有7个类别,实际上就是七个头指针,不同大小的chunk释放后会连到不同的头指针后面。然后fastbin是单向链表连接的,而且是用插头法插入因为这样快,这也就导致了一个现象FIFO,后进先出,后面进来的chunk更快被分配出去,然后我们看到0x602020后面连接了0x602000,他们的连接就是用的fd指针,这也就是为什么三个chunk释放却只有一个chunk有fd

posted @ 2022-03-03 19:56  予柒  阅读(330)  评论(0)    收藏  举报
返回顶端
Live2D /*修改地一:waifu.css*/
/*修改地二:waifu.css*/
/*修改地三:live2d.js*/ /*修改地四:waifu-tips.js*/