GLIBC 2.31(ptmalloc) 堆管理器--基础知识

admin 2021年9月3日07:28:54评论81 views字数 1834阅读6分6秒阅读模式

 

在堆溢出的利用中,随着GLIBC的不断更新,添加了越来越多的保护,对size与presize的检测,对链表完整性的检测等。使得堆上的利用难度不断增大。

这里开始分析部分ptmalloc的实现部分(64位),为新版本GLIBC堆利用,以及设计内存池提供一些思路。

首先是祖传的_int_malloc函数。

GLIBC 2.31(ptmalloc) 堆管理器--基础知识

其中av是堆的全局信息,包括被释放的堆内存,堆已分配大小,剩余空间指针,已向系统分配但未使用的堆指针等,主线程会有一份放置在libc的全局变量中(叫main_arena):bytes表示通过malloc传入的欲分配的大小。

mstate:

GLIBC 2.31(ptmalloc) 堆管理器--基础知识

GLIBC 2.31(ptmalloc) 堆管理器--基础知识

首先大致写出ptmalloc的堆块管理的一些机制:

我们知道malloc在分配小内存的时候不会申请多少就分配多少,而是先分配出一大块内存。因为频繁向系统申请内存是相当耗费时间的。

然后将其切下一小块递给用户。而随着分配释放的频率、大小、数量的变化,使得在维护这些不断变动、切割的内存块变得比较困难。保证效率的情况下还需要保证内存碎片尽量少。因此ptmalloc添加了若干个缓冲池(bin):

tcache bin

fast bin

unsorted bin

small bin

large bin

等。如果分配的内存过大,可能会直接考虑向系统分配,释放则也是直接归还系统。

堆块(chunk):

堆块指使用malloc真正划分出的一块内存结构。程序在使用malloc的时候指定的size以表示需要多少内存。而在free中并没有要求用户指定free的大小,那么glibc怎么知道应该释放多少内存的呢?其实这个长度的信息就在分配给用户的内存上方。malloc分配的内存并不是用户指定的大小,而比这要大一些,然后将当前分配的一些信息写入开头,随后将属于用户的那段空间返回给用户。头部的那些信息对使用者是透明的。

相关代码:


那么堆块头信息除了堆块长度包含着些什么呢?glibc为了节约空间,堆块在不同的环境下的结构信息含义是不一样的。

最简单的情况就是已分配出去时堆块头信息(64位):

假如这里分配一个0x30大小的堆空间:

presize

size | A | M | P |

???????

0x4?

用户空间(0x30大小)


presize:在内存地址相邻的上一个堆块是被free的情况下表示上一个堆块大小,在使用的情况下作为上一个堆块的一部分。

size:表示本堆块大小(不是用户区域大小),由于分配堆块需要按照指定内存对齐(64位16字节,32位8字节),因此堆块大小的值总是8的倍数最低为都为0,为了避免浪费。最低3位用来分别表示A、M、P标识


A(NON_MAIN_ARENA) :表示当前堆块是否不是用主线程的堆块信息分配出来的。

M(IS_MMAPPED): 表示当前堆块是否是直接通过mmap分配出来的。(如果是,在free时检查到这个位直接使用unmap归还系统)

P(PREV_INUSE): 表示内存地址相邻上一个堆块是否在被使用中。可以暂时理解为被malloc的堆块,但实际上某些情况下free之后仍然会保留自身的INUSE位。

以及另一种情况,例如分配两个0x28的长度堆块,分别填满A与B,可以发现当第一个堆块属于在被使用时,下一个堆块的prev_size作为用户空间分给了第一个堆块。(off by one 重点

堆块1

prevsize

size | A | M | P |

????????

0x3?

(用户数据)AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

堆块2

prevsize

size | A | M | P |

AAAAAAAA

0x31

BBBBBBBB

BBBBBBBBB

BBBBBBBB

BBBBBBBB

BBBBBBBB

0x????1

 

被释放后的堆块根据所在的bin结构有所差异。

以及两个特殊的chunk(堆块):

这两个chunk是直接由arena进行管理的。

top chunk:用于在任何bin中都找不到合适的堆块进行分配时,划分的堆块,如果这个堆块也不够,则会分配一个更大的top chunk进行切割,原先的top chunk会变成free的堆块被挂在适当的bin中。

last remainder chunk:当发生堆块的切割时,记录最近一次切割剩下的堆块,如 释放了0x1000的堆块,随后又分配了0x500,glibc会为剩下的0xa00构造成一个被释放的堆块,last remainder指针将会指向这个堆块。


本文始发于微信公众号(锋刃科技):GLIBC 2.31(ptmalloc) 堆管理器--基础知识

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年9月3日07:28:54
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   GLIBC 2.31(ptmalloc) 堆管理器--基础知识http://cn-sec.com/archives/398970.html

发表评论

匿名网友 填写信息