堆概述

Posted by nop on 2020-02-03
Words 628 In Total

概述

堆不同于栈,堆是动态分配的(由操作系统内核或者堆管理器),只有在程序中需要时才会分配。在 CTF 的 pwn 程序中,栈是程序加载进内存后就会出现,而堆是由 malloc、alloc、realloc 函数分配内存后才会出现。

Alt

堆的生长方向是从低地址向高地址生长的,而栈是从高地址向低地址生长的

实际上堆可以申请到的内存空间比栈要大很多,在 linux 的 4G 的虚拟内存空间里最高可以达到 2.9 G 的空间。
对堆操作的 是由堆管理器(ptmalloc2)来实现的,而不是操作系统内核 。因为程序每次申请或者释放堆时都需要进行系统调用,系统调用的开销巨大,当频繁进行堆操作时,就会严重影响程序的性能。

glibc库下的 ptmalloc2 堆管理器

堆的基本结构

Alt

  1. pre size 字段。只有在前面一个堆块空闲的时候才有值,用来指示前面一个堆块的大小。前面一个堆块在使用时,pre size的值始终为0
  2. size 字段。用来指示当前堆块的大小(头部加上user data的大小)。这个字段的低三位的作用:
    • NON_MAIN_ARENA 这个堆块是否位于主线程
    • IS_MAPPED 记录当前 chunk 是否是由 mmap 分配的
    • PREV_INUSE 记录前一个 chunk 块是否被分配
      PREV_INUSE 用来记录前一个 chunk 块是否被分配,被分配的话这个字段的值为 1 ,所以经常会在已分配的堆块中的 size 字段中发现值比原来大 1 个字节(表示前一个chunk已被分配)

64位程序

malloc(8)

申请到的堆块总大小为 16 + 8 + (8 + 1) = 0x21

  1. 第一个 16 字节是系统最小分配的内存 ,即如果申请的内存小于系统最小分配的内存的话,就会按照最小的内存来分配。(在 64 位系统中这个值是 16 个字节,在 32 位系统中是 8 个字节,比如 malloc(0) 会分配16字节或8字节的内存)

  2. 第二个 8 字节是 pre size 字段的大小(32 位的为 4 字节)

  3. 第三个 8 字节为 size 字段的大小(32 位的为 4 字节)

  4. 最后一个 1, 表示前一个chunk在使用,所以size字段最低位变为1, 导致size的值加一

内存分配:

Alt

内存回收:

Alt


You are welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them.