• pwn 堆基础


    堆申请

    堆简介

    堆是用malloc函数申请使用的。
    在这里插入图片描述
    假设我们通过void * ptr = malloc(0x10);申请一块内存时:

      1. 系统会调用一些函数在内存中开辟一大片空间作为堆的分配使用空间。
      1. malloc函数再从这篇堆的分配使用空间中分配0x10大小的空间,将指向该空间的地址返回给ptr(余下的空间称之为topthunk)
        在这里插入图片描述

    示例程序

    #include 
    #include 
    int main(){
            void *ptr = malloc(0x10);
            void *ptr1= malloc(0x90);
            void *ptr2= malloc(0x800);
            return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    我们gdb调试下该程序,执行b main–> vmmap查看内存情况,发现并没有堆空间分配情况:
    在这里插入图片描述
    接下来我们让程序执行第一次调用malloc时,查看内存情况,可以看到存在一块堆空间,并且分配了0x2100大小的堆空间
    在这里插入图片描述
    查看heap空间分配,发现我们明明只malloc(0x10),但却申请了0x21大小的空间。
    在这里插入图片描述

    chunk

    定义

    chunk:用户申请内存的单位,也是堆管理器管理内存的基本单位 malloc()返回的指针指向一个chunk的数据区域
    在这里插入图片描述

    运行过程中被malloc分配的内存为一个chunk,这块内存在ptmalloc中用malloc_chunk结构体表示,当程序申请的chunk被free时,会被加入相应的空闲管理列表中。

    chunk分类

    在这里插入图片描述
    使用中的chunk:已被分配且填写了相应数据
    在这里插入图片描述

    空闲中的chunk(被free 后):
    在这里插入图片描述
    可以发现chunk被free掉,多了红色框框的字段。
    chunk神奇之处就在于,chunk虽然由一个统一的结构体声明,但被使用时和空闲时却又有两种不同的状态。

    chunk结构体解析

    在这里插入图片描述

    1. prev_size:如果前一个chunk是空闲的,该域表示前一个chunk的大小,如果前一个chunk不空闲,该域毫无意义
    2. size:当前chunk大小,并且记录了当前chunk和前一个chunk的一些属性(通过二进制后三位记录)。
    3. FD:记录了下一个被free的chunk(used only if free),即下一个被free掉的chunk
    4. BK:记录了上一个被free的chunk(used only if free),即上一个被free掉的chunk
    5. fd_nextsize 和 bk_nextsize,largebin使用,记录上/下一个被free chunk的size

    以使用中的chunk为例,可以发现size字段后面三位为A、M、P,用于标记一些属性。因为地址对齐后三位必须为0,所以就将后三位拿来作为标志位使用,这里主要记住P标志位:前一个chunk是否被使用
    在这里插入图片描述

    chunk复用技术(prev_size)

    prev_size字段记录的信息存在两种情况

    1. 如果前一个邻接chunk块空闲,那么当前chunk块结构体的prev_size字段记录的是前一个邻接chunk块大小。这就是由当前chunk指针获得前一个空闲chunk地址的依据。
    2. 如果前一个邻接chunk在使用中,则当前chunk的prev_size的空间被前一个chunk借用,其中的值是前一个chunk的内容,对当前chunk没有任何意义。

    堆的释放

    堆的释放一般都用free函数实现,但是free后chunk去哪了呢?其实在bins中,这块先讲解堆释放管理过程

    堆释放后的管理

    堆释放后,会被添加到相应的bins中进行管理,这里涉及的结构体是malloc_state。
    分箱式管理:对于空闲chunk,ptmalloc采用分箱式内存管理方式,根据空闲chunk大小和处于的状态将其放在四个不同的bin中,这四个空闲的chunk容器包括:fast bins、unsorted bin、small bins和large bins

    bins讲解

    glibc malloc分配了若干个bins,为了方便查找,glibc提供两个数组:fastbinY和bins
    bins其实就是垃圾桶。在这里就是存放没有用的chunk,即被free的chunk
    在这里插入图片描述

    示例程序

    #include 
    #include 
    int main(){
            void *ptr = malloc(0x10);
            void *ptr1= malloc(0x10);
            void *ptr2= malloc(0x10);
            void *ptr3= malloc(0x10);
            free(ptr);
            free(ptr1);
            free(ptr2);
            free(ptr3);
            malloc(0x150);
            return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    gdb调试,使其申请4个chunk
    在这里插入图片描述
    这是我们释放2个malloc,查看bins,tcache(thread local caching)是glibc2.26之后引入的一种新机制。他和fastbin很相似,这里就把他当作fastbin就行,无伤大雅!!
    我们可以看到0x20处由一个单链表,链着两个地址,这两个地址就是刚刚free的
    在这里插入图片描述

    fast bins

    Fast bins主要是用于提高小内存的分配效率,默认情况下对于size_sz为4B的平台,小于64B的chunk分配请求和对于size_sz为8B的平台,小于128B的chunk分配请求,首先会查看fast bins中是否存在所需要大小的chunk存在,如果存在,就直接返回。
    fastbinsY拥有10个(上图为7个)元素的数组,用于存放每个fast chunk链表头指针,所以fast bins最多包含10个fast chunk的单链表

    unsorted bin

    unsorted bin可以看作是small bins和large bins的cache,只有一个unsorted bin,以双链表管理空闲chunk,空闲chunk不排序

    bins

    bins用于存储unstored bin,small bins, 和large bins的chunk链表头,所有的chunk在回收时都要放到unsorted bin中,分配时,如果在unsorted bin中没有合适的chunk,就会把unsorted bin中的所有chunk分别加入到所属的bin中,然后再在bin中分配合适的chunk。

  • 相关阅读:
    Leiden算法介绍
    你必须学UML之理论篇
    解决json-editor-vue3光标错位问题
    apple pencil性价比高吗?适用ipad的电容笔推荐
    postgresql-常用日期函数
    电镀废水末端除镍工艺,除镍树脂如何使用?
    用DIV+CSS技术设计的凤阳旅游网站(web前端网页制作课作业)HTML+CSS+JavaScript
    第三章 内存管理 一、内存的基础知识
    【Java 进阶篇】MySQL 数据控制语言(DCL):管理用户权限
    Llama2-Chinese项目:7-外延能力LangChain集成
  • 原文地址:https://blog.csdn.net/qq_41696518/article/details/126677930