PWN_glibc堆管理机制及内存结构(入门篇)

一、什么是堆

堆是内存中一片连续的区域,CTF中glibc的题型主要集中在栈、堆、linux内核,其中堆占很大一部分比重

内存中栈区域操作区域从高地址向低地址增长,堆相反,是从低地址向高地址增长

二、堆实现及存储机制

堆是内存中一片固定内存区域,程序通过进程申请(malloc)、释放(free)堆空间,下面提到的堆都是指进程管理的堆空间

堆的glibc实现主要通过三个结构体,struct heap_info, struct malloc_state, struct malloc_chunk,

这三个结构体由arena控制管理。每个程序中arena数量都是有限的,通常通过以下原则规定:

32位系统下:
number of aerna = 2 * cores + 1
64位系统下:
number of arena = 8 * cores + 1

一个进程只有一个arena(甚至可能没有arena,更加复杂的情况在此不作讨论),主进程的arena叫做main_arena,子进程的arena叫做thread_arena

下面我们从堆内存最小单元chunk开始,分析下struct heap_info, struct malloc_state, struct malloc_chunk, 这三个结构体作用,及堆管理机制

chunk是堆内存中的最小单元,struct malloc_chunk描述了chunk结构

struct malloc_chunk {
 
  INTERNAL_SIZE_T      mchunk_prev_size;  /* Size of previous chunk (if free).*/
  INTERNAL_SIZE_T      mchunk_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;
 
};

上述结构体描述的是chunk在被free状态下的结构,如果chunk在使用,则只包含pre_size, size, user_data三部分

下面分chunk在使用,未被使用两部分讨论malloc_chunk结构体

在这里插入图片描述

当chunk1在使用时,如果与chunk1物理相邻的上一个chunk2也在使用(pre_inuse = 1),则pre_size供chunk2使用;mchunk_size指当前chunk的大小(pre_size+size+user_data),由于页映射机制,size后三位无法表示大小,引入A、M、P三位,分别表示是否是主线程(main_arena), 是否通过mmap()函数分配(is_mmapped),上一个chunk是否在使用(pre_inused);fd, bk, fd_netsize, bk_nextsize此时被user_data填充,不发挥作用

当chunk1未被使用时,pre_size表示上一个空闲chunk的大小;size表示当前chunk大小;fd指向下一个chunk的首地址(pre_size位置),bk指向上一个chunk的首地址;fd_nextsize,bk_nextsize指向largebin链表中的chunk

当我们向堆内存申请空间时(如malloc(8)),glibc需要向用户返回一块堆内存区域(即一个chunk),那么chunk是怎样被选取的呢?

那就来到struct malloc_state的作用了

struct malloc_state
{
  /* Serialize access.  */
  __libc_lock_define (, mutex);
 
  /* Flags (formerly in max_fast).  */
  int flags;
 
  /* Set if the fastbin chunks contain recently inserted free blocks.  */
  /* Note this is a bool but not all targets support atomics on booleans.  */
  int have_fastchunks;
 
  /* Fastbins */
  mfastbinptr fastbinsY[NFASTBINS];
 
  /* Base of the topmost chunk -- not otherwise kept in a bin */
  mchunkptr top;
 
  /* The remainder from the most recent split of a small request */
  mchunkptr last_remainder;
 
  /* Normal bins packed as described above */
  mchunkptr bins[NBINS * 2 - 2];
 
  /* Bitmap of bins */
  unsigned int binmap[BINMAPSIZE];
 
  /* Linked list */
  struct malloc_state *next;
 
  /* Linked list for free arenas.  Access to this field is serialized
     by free_list_lock in arena.c.  */
  struct malloc_state *next_free;
 
  /* Number of threads attached to this arena.  0 if the arena is on
     the free list.  Access to this field is serialized by
     free_list_lock in arena.c.  */
  INTERNAL_SIZE_T attached_threads;
 
  /* Memory allocated from the system in this arena.  */
  INTERNAL_SIZE_T system_mem;
  INTERNAL_SIZE_T max_system_mem;
}; 

chunk通过bins数组管理,bins数组又可以分为很多类,包括fastbins,smallbins,largrbins, unsortbin等

可以看到,malloc_state结构体中对bins数组的描述有两处,fastbinsY和bins[NBINS * 2 - 2]

在这里插入图片描述

fastbinsY指管理fastbins的数组,fastbin中的freechunk具有如下特点:一是fastbin索引的bin头大小确定,二是fatbin只有fd指针,单向链表(所有类型的bin中也只有fastbins是单向链表),后进先出,三是pre_inuse位总是置1

在这里插入图片描述

bins数组管理其余三种bins链表(smallbins, largebins, unsortbin)。一个bins数组中各个bin是连在一起的,结合下图可以分析下bins数组的工作模式

bins[0]为空,bins[1]管理unsortbin的双向循环链表,只有bins[1]管理,也因此后面没有加’s’。unsortbin管理刚释放且未分类的chunk,可以视作chunk分配前的缓冲区。

bins[2]-bins[63]为62个双向循环链表,管理smallbins中的chunk,先进先出,精准匹配chunk大小,在32位下分别是16,24…,504(64位下乘2即可)。

largebins在bins数组中占据bins[64]-bins[126],63个双向循环链表,先进先出,每一个bin管理一个范围内的chunk(32位下大于504,比如504-1024达大小的由bins[64]管理)。

bins数组再上一层就是堆段管理了 ,由struct heap_info结构体负责

typedef struct _heap_info
{
  mstate ar_ptr;            /* Arena for this heap. */
  struct _heap_info *prev;  /* Previous heap. */
  size_t size;              /* Current size in bytes. */
  size_t mprotect_size;     /* Size in bytes that has been mprotected
                             PROT_READ|PROT_WRITE.  */
  /* Make sure the following data is properly aligned, particularly
     that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
     MALLOC_ALIGNMENT. */
  char pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK];
} heap_info;

一个线程可以包含多个堆段,而多个堆段的信息就是通过该结构体来管理实现的。该结构体不是存储堆段数据,二是解释堆段管理信息。

三、堆管理

malloc

malloc一个chunk,首先在unsortedbin中遍历,如果匹配到合适大小的直接取走,否则将unsortbin中为分类的chunk全部分类到相应的bins,再到合适的bins中去取

free

chunk在free后,如果该chunk的大小和fastbin匹配,就直接放到fastbins里,或者就放unsortbin

不足之处还请指正,欢迎师傅们留言~

参考文献:

[1] csdn_董哥的黑板报,链接:

https://so.csdn.net/so/search?spm=1010.2135.3001.4498&q=%E8%91%A3%E5%93%A5%20%E5%A0%86%E6%BC%8F%E6%B4%9E&t=&u=

[2] bili_星盟师傅,链接(第10-12节):

https://www.bilibili.com/video/BV1854y1y7Ro/?p=11&spm_id_from=333.1007.top_right_bar_window_history.content.click

[3] 《CTF竞赛权威指南》第十一章 堆利用

bili_星盟师傅,链接(第10-12节):

https://www.bilibili.com/video/BV1854y1y7Ro/?p=11&spm_id_from=333.1007.top_right_bar_window_history.content.click

[3] 《CTF竞赛权威指南》第十一章 堆利用

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值