堆的调用流程、堆漏洞挖掘中的malloc_chunk结构体分析

一、堆的调用流程

第一步

  • 当应用程序“第一次”使用malloc函数申请动态内存时,glibc库会向内核申请一块非常大的动态内存,这块动态内存会比malloc申请的大小大很多。
  • brk/mmap系统调用:glibc库使用的是brk或者mmap系统调用来想内核申请内存空间的。至于两者有什么区别后面介绍。

第二步

  • glibc申请到这块大的内存之后,根据malloc需要的大小,然后切割相应的大小给应用程序malloc函数使用。

第三步

  • 当应用层free之后,会将刚才使用到的动态内存返回给glibc,但是返回的内存不是返回给top chunk,而是由bins链管理(后面会介绍bins链)。

第四步

  • 当程序再次malloc时,会从刚才申请的很大的动态内存去取,不会再去向内核申请内存。
  • 只有当第一次申请的动态内存使用完时,glibc才会再次通过brk/mmap系统调用向内核去要内存。

二、细节介绍

struct malloc_chunk结构体

  • 堆是由一系列struct malloc_chunk结构体组成的链表,申请和释放的堆都是malloc_chunk结构体。
  • 其他文章会详细介绍此结构体。

bin链

  • 当应用层malloc申请的内存使用完之后,通过free函数将堆内存(也就是struct malloc_chunk结构体)返回给glibc时,不返回给top chunk,而是由称为bin的链所管理。因此bin链也是由struct malloc_chunk组成的链表。
  • bins链分为:fastbin、smallbin、unsorted bin、large bin。
  • 其他文章会详细介绍bin链。

arena

  • 由于堆中存在许多的信息,例如各种bin链、chunk结构体等,这些东西需要管理,就是通过arena来管理的。
  • arena分为main_arena和thread_arena。
  • arena由struct malloc_state结构体实现。

三、一些相关概念

  • ①malloc是应用层的概念,malloc申请的内存实际上是由glibc通过brk和mmap系统调用向内核申请的。
  • ②第一次malloc申请的内存是一块非常大的内存,这块内存供程序后面多次调用malloc使用。只有当这块非常大的动态内存使用完之后,glibc才会再次通过brk/mmap系统调用向内核去要内存;否则,glibc不会再通过brk/mmap系统调用向内核要内存。
  • ③虽然第一次malloc,操作系统分配给程序一块很大的内存,但这块内存只是虚拟内存,只有当用户使用到相应的内存时,系统才会真正分配物理页面给用户使用。
  • ④第一次申请的大的动态内存称为“top chunk”。
  • ⑤free函数返回的堆内存不是返回给“top chunk”,而是由glibc中称为bin的链接收和管理。

四、struct malloc_chunk

struct malloc_chunk {

  INTERNAL_SIZE_T      mchunk_prev_size;
  INTERNAL_SIZE_T      mchunk_size;

  struct malloc_chunk* fd;
  struct malloc_chunk* bk;

  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  struct malloc_chunk* bk_nextsize;

};
  • 每个成员都是8字节(64位系统中),4字节(32位系统中)。

 mchunk_prev_size、mchunk_size

  • mchunk_prev_size:只有当该chunk的物理相邻的前一地址chunk是空闲的话,该字段在本chunk中才有用,用来记录前一个chunk 的大小 (包括chunk头)。否则,该字段为0是没有用的;但是当前一个chunk申请的大小大于前一个chunk的大小时,那么该字段可以用来给前一个chunk使用(这就是chunk的空间复用,后面文章介绍)。
  • mchunk_size:当前chunk的大小。

fd、bk

  • 当前chunk处于分配状态时:从fd字段开始的是用户的数据。
  • 当前chunk处于空闲时:
    • 因为chunk处于空闲时,会被放到bin链中,所以fd和bk用于指向自己所在bin链中前后的空闲chunk
    • fd:指向前一个(非物理相邻)空闲的 chunk的指针(头指针)。
    • bk:指向后一个(非物理相邻)空闲的 chunk的指针。
    • 通过fd和bk可以将空闲的chunk块加入到空闲的chunk块链表进行统一管理。

fd_nextsize、bk_nextsize

  • 也是只有chunk空闲的时候才使用,不过其用于较大的chunk(large chunk):
    • fd_nextsize:指向前一个与当前 chunk 大小不同的第一个空闲块,不包含bin的头指针。
    • bk_nextsize:指向后一个与当前 chunk 大小不同的第一个空闲块,不包含 bin 的头指针。
  • 一般空闲的 large chunk 在 fd 的遍历顺序中,按照由大到小的顺序排列。这样做可以避免在寻找合适 chunk 时挨个遍历。

五、结构体大小的对齐原则

  • 原则:struct malloc_chunk结构体的大小必须是2 * SIZE_SZ的整数倍。如果申请的内存大小不是2 * SIZE_SZ 的整数倍,会被转换满足大小的最小的2 * SIZE_SZ 的倍数(32位系统中,SIZE_SZ是4;64 位系统中,SIZE_SZ是8)。
  • 当前chunk结构体的大小用mchunk_size成员的值表示。

  • 我是小董,V公众点击"笔记白嫖"解锁更多【堆漏洞挖掘】资料内容。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董哥的黑板报

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值