随笔 - 5  文章 - 0  评论 - 3  阅读 - 168

堆基础(未完,持续更新)

堆利用入门

堆管理器

堆概述

image

堆的概念

堆是虚拟内存空间的一段连续的线性区域,提供动态分配的内存,允许程序申请大小未知的内存。再用户与操作系统之家按,作为动态内存管理的中间人,响应程序的申请内存请求,向操作系统申请内存,然后返回给程序。并且管理用户所释放的内存,适时归还给操作系统。

各种堆管理器

  • dlmalloc -General Purpose allocator
  • ptmalloc2 - glibc
  • jemalloc - FreeBSD and Firefox
  • tcmalloc - Google libumem - Solaris

堆管理器并非由操作系统实现,而是由libc.os.6链接库实现的。该库封装了一些系统调用,位用户提供了方便的动态内存分配接口的同时,力求高效地管理由系统调用申请来的内存。

申请内存的系统调用

  • brk
  • mmap
    image

Areana

内存分配区,可以理解为堆管理器所持有的内存池。
对管理器与程序的内存交易发生在arena中,可以理解为对管理器向操作系统批发来的由冗余的内存库存。

操作系统 -> 堆管理器 -> 程序
物理内存 -> arena -> 可用内存

chunk

概述

程序申请内存的单位,也是堆管理器中管理内存的基本单位。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. */
    
    /* Doubly linked -- used only if free. */
    struct malloc_chunk* fd;           /* Forward pointer to next chunk in list. */
    struct malloc_chunk* bk;           /* Back pointer to previous chunk in list. */
    
    /* Doubly linked -- used only if free and in a large bin. */
    struct malloc_chunk* fd_nextsize;  /* Forward pointer to next larger chunk in list. */
    struct malloc_chunk* bk_nextsize;  /* Back pointer to previous larger chunk in list. */
};

chunk的分类

按状态
  • malloced:已经分配且填写了数据的chunk。image
  • free:被释放掉的malloced chunk成为free chunk。image
按大小
  • fast
  • small
  • large
  • tcache
按特定功能
  • top chunk:arena中从未被使用过的内存区域。image
  • last remainder chunk:free大堆块之后重新用malloc分割chunk后剩余的部分。image

堆的大小对齐

堆的大小必须是MALLOC_ALIGNMENTd的整数倍,如果申请的大小不是MALLOC_ALIGNMENT的整数倍,会被转换成满足条件的最小的值。32 位系统中, MALLOC_ALIGNMENT 可能是 4 或 8 ;64 位系统中,MALLOC_ALIGNMENT 是 8或 16。我们可以发现,不管size的大小如何变,size的低三位都为0,为了不浪费这三个比特位,他们从高到低分别用来表示(AMP):

  • NON_MAIN_ARENA:记录当前chunk是否不属于主线程,1表示不属于,0表示属于。
  • IS_MAPPED:记录当前chunk是否由mmap分配。
  • PREV_INUSE:记录前一个chunk块是否被分配。

chunk的微观结构

image

chunk结构的分析

  • prev_sizee:若前一个物流相邻的chunk是free chunk,泽尔表示其大小。否则被用于储存前一个chunk的数据。
  • size:前三个比特位存放AMP占据一字长的低3比特以后的地址,用于表示当前chunk的大小(整个chunk的大小,包括 chunk头)。
    -A flag:NON_MAIN_ARENA:记录当前chunk是否不属于主线程,1表示不属于,0表示属于。
    -M flag:IS_MAPPED:记录当前chunk是否由mmap分配。
    -P flag:PREV_INUSE:记录前一个chunk块是否被分配。一般来说,堆中第一个被分配的内存size字段的P为都会被设置为1,以便于防止访问前面的非法内存。当一个chunk的size的P位为0时,我们能通过prev_size字段来获取上一个chunk的大小以及地址。这方便chunk之间的合并。
  • fd pointer:bin中指向下一个(不一定物理相邻)空闲的chunk。
  • bk pointer:bin中指向上一个(不一定物理相邻)空闲的chunk。
  • fd_nextsize:large bin中指向前一个与当前chunk大小不同的第一个空闲块(不包含bin的头指针)。
  • bk_nextsize:large bin中指向后一个与当前chunk大小不同的第一个空闲块(不包含bin的头指针)。

Bin

为了方便理解,下面将用一下代码演示下面提到一部分bin

#include <stdlib.h>
#include <malloc.h>
int main ()
{   
   mallopt(1,0);
   int *a = malloc(0x10);
   int *b = malloc(0x10);
   int *c = malloc(0x10);
   free(b);
   free(a);//fastbin
   mallopt(1,0);// 修改global_max_fast = 0, 进入 unsorted bin
   malloc(0x50);//进入small bin
   return 0;
}

bin的概述

管理arena中空闲的chunk的机构,以数组的形式存在,数组元素为相应大小的chunk链表的链表头,存在于arena的malloc_state中。

bin

的分类

fast bins

单向链表,管理16、24、32、40、48、56、64 Bytes的free chunks(32位下默认)其中的chunk的in_use位(下一个物理相邻的chunk的P位)总是为1,LIFO(Last In, First Out)。
image

unsorted bin

双向链表结构,管理刚刚释放还未分类的chunk。
image
关闭fastbin,再查看bin的情况。
image
我们再申请大于0x40空间的堆块。刚才unsortedbin中的堆块就会回归small bin。
image

small bins

下面使用以下代码进行演示

#include <stdio.h>
int main ()
{
    int *a = malloc(0x10);
    int *b = malloc(0x10);
    int *c = malloc(0x10);
    int *d = malloc(0x10);
    int *e = malloc(0x20);
    int *f = malloc(0x20);

    free(a);
    free(c);
    free(e);
    
    int *g = malloc(0x400);
    return 0;
}

bins[2] ~ bins[63],62个循环双向链表,FIFO机制,管理16、24、32、40....504 Bytes的free chunks(32位)每个链表中存储的chunk大小都一致。
image

large bins

使用一下代码演示

#include <stdio.h>
int main ()
{
int *a = malloc(0x400);
int *b = malloc(0x410);
int *c = malloc(0x420);
int *d = malloc(0x430);
int *e = malloc(0x440);
int *f = malloc(0x450);

free(a);
free(c);
free(e);

malloc(0x500);
return 0;

}

bins[64]~bins[126],63个循环双向链表,FIFO机制,管理大于504Bytes的free chunkss(32位)每个链表中存贮的chunk大小再一个范围内。
image
image
image

(tcache)glibc-2.24以后

堆分配策略

Malloc

根据程序申请的内存大小以及相应大小的chunk通常使用的频度(fastbin chunk、small chunk、large chunk)依次实现不同的分配方法。它由小到大一次检查不同的bin中是否由相同相应的空闲块可以满足用户请求的内存。当所有空闲的chunk都无法满足时,他会考虑top chunk。当top chunk也无法满足时,堆分配器会进行内存块申请。

free

将程协暂时不用的chunk回收给堆管理器,适当的时候把内存归还操作系统。根据chunk的大小来优先试图把free chunk链如tcache或者fast bin,不满足则链入unsorted bin并将其中的物理相邻的free chunk合并,将相应大小的chunk分类放入small bin或large bin中。除了tcache chunk和fast bin chunk以外,其他的chunk在free时会与其物理地址相邻的free chunk合并。

堆漏洞及其利用

posted on   丶落雪  阅读(31)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示