查看: 149|回复: 0

[Pwn] 堆入门的必备基础知识

[复制链接]
发表于 2020-6-11 16:27:55 | 显示全部楼层 |阅读模式
  文章目录

    • 前言
    • 堆的实现原理
    • 0×00 创建、释放堆的函数
      • malloc 函数:
      • free 函数:
    • 0×01 内存分配有关的函数
      • 示例:
    • 0×02 mmap、munmap函数
      • prot参数指定虚拟内存区域的访问权限,有以下几个
      • flags参数描述被映射对象类型的位组成,有以下几个
      • mmap 函数与 brk 函数的区别
      • mmap 函数的另一种用法
      • 分配的过程:
    • 0×03 堆的使用场景
    • 0×03 Bin
      • fast bins
    • 参考文章
  • 大家有任何问题可以提问,更多文章可到i春秋论坛阅读哟~
  i春秋作家:W1ngs
  原文来自:堆入门的必备基础知识
前言  堆的利用相对于栈溢出和格式化字符串会复杂很多,这里对堆的一些基本知识点和实现原理进行了一些小小的总结,写的如有不当恳请大佬们斧正。
堆的实现原理
  对堆操作的是由堆管理器来实现的,而不是操作系统内核。因为程序每次申请或者释放堆时都需要进行系统调用,系统调用的开销巨大,当频繁进行堆操作时,就会严重影响程序的性能
  例如 glibc 中使用了 ptmalloc2 作为堆管理器:
  目前 Linux 标准发行版中使用的堆分配器是 glibc 中的堆分配器:ptmalloc2。ptmalloc2 主要是通过 malloc/free 函数来分配和释放内存块。
  程序向系统申请堆空间的时候相当于一种 ”批发” 和 “零售” 的关系:
  堆管理器就像一个中间商,将向内核申请到空间根据分配算法来把空间真正的分配给程序。
  这里为了理解简单画了一张图,如果有错误的话敬请指正。

堆入门的必备基础知识

堆入门的必备基础知识
0×00 创建、释放堆的函数
malloc、realloc、calloc
malloc 函数:
#include <stdlib.h>  void *malloc(size_t>
[list]
  • 在使用malloc的时候要进行强制类型转换为指针类型   malloc函数申请地址成功后返回一个指针,指向大小为至少size字节的内存块 [list]
  • 当size = 0 时,返回当前系统允许的堆的最小内存块  即malloc(0) 在32位系统下会分配 8 个字节的空间,在 64 位系统下会分配 16 字节的空间 [indent]  malloc会使用 mmap 来创建独立的匿名映射段,malloc 的背后是用 brk 函数来实现内存地址申请的。   查看方法:cat /proc/PID/maps

    堆入门的必备基础知识

    堆入门的必备基础知识
    [indent]  使用 malloc() 申请的内存,释放后,仍然归还回原处,再次申请同样大小的内存区时,还是从第 1 次那里获得   每次申请会获取比申请到更大的值,这样的话,就避免了多次内核态与用户态的切换,提高了程序的效率 [indent]  分配器视堆为一组不同大小的块(chunk)的集合。每个块就是一个连续的虚拟内存片。 [b]free 函数:[pre]#include <stdlib.h>  void free(void *ptr);

  •   free 函数会释放由 p 所指向的内存块,这个内存块可以是通过malloc或者readlloc函数分配的块。
    • 当 p 为空指针时,函数不执行任何操作,当释放过 p 内存块再次释放后,会产生错误(double free)。
      当一个堆块释放了(通过调用free函数),它会检查之前的堆块是否被释放了。如果之前的堆块没有在使用,那么就会和当前的堆块合并。
      unlink 的源码:
    /* Take a chunk off a bin list */  void unlink(malloc_chunk *P, malloc_chunk *BK, malloc_chunk *FD)
      {
      FD = P->fd;
      BK = P->bk;
      FD->bk = BK;
      BK->fd = FD;
      }

      chunk 合并的过程与双向链表删除节点的过程相同:

    堆入门的必备基础知识

    堆入门的必备基础知识
      其实这块论坛里有一篇关于 unlink 函数的利用这一块讲的很清楚了,可以参考他的文章:
      https://bbs.ichunqiu.com/thread-46614-1-1.html
    0×01 内存分配有关的函数
    brk  sbrk

    堆入门的必备基础知识

    堆入门的必备基础知识
      对于每个堆,变量brk指向堆的顶部,不过有下面的两个前提
    • 不开启 ASLR 保护时,brk 会指向 data/bss 段的结尾。
    • 开启 ASLR 保护时,brk 也会指向同一位置,只是这个位置是在 data/bss 段结尾后的随机偏移处。
      brk和sbrk主要的工作是实现虚拟内存到内存的映射
    • 当 sbrk() 中的参数为 0 时,我们可以找到 program break 的位置。 也就是 sbrk(0) 时,指针指向的就是program break,也就是堆顶

    堆入门的必备基础知识

    堆入门的必备基础知识
    • brk 函数和 sbrk 函数通常都配合使用,如下示例:
    示例:  1.sbrk(0) — >  初始化堆,将 start_brk 以及堆的当前末尾 brk 指向同一地址
      在执行下面的两条语句之后,使用 cat /proc/PID/maps 会发现没有堆空间
    tmp_brk = curr_brk = sbrk(0);  printf("Program Break Location1:%p\n", curr_brk);

    堆入门的必备基础知识

    堆入门的必备基础知识
      2.brk(curr_brk+4096) — > 重新定义堆顶的指针
    brk(curr_brk+4096);  curr_brk = sbrk(0);
      printf("Program break Location2:%p\n", curr_brk);

    堆入门的必备基础知识

    堆入门的必备基础知识
      3.此时再调用 sbrk(0),堆顶指针就会变化
     brk(tmp_brk);  curr_brk = sbrk(0);
      printf("Program Break Location3:%p\n", curr_brk);

    堆入门的必备基础知识

    堆入门的必备基础知识
    0×02 mmap、munmap函数
      mmap函数要求内核创建一个新的虚拟内存区域
      map函数原型:
    void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset)
    prot参数指定虚拟内存区域的访问权限,有以下几个
    PROT_EXEC    //这个区域由可以被CPU执行的指令组成  PROT_READ    //可读
      PROT_WRITE   //可写
      PROT_NONE    //不可访问

    flags参数描述被映射对象类型的位组成,有以下几个
    MAP_ANON或者MAP_ANONYMOUS    //表示被映射的对象是一个匿名对象,相应的虚拟页面是请求二进制零的  MAP_PRIVATE                 //对象属性为私有、写时复制的
      MAP_SHARED                  //表示共享对象

    • 对于大于 128 KB 的堆申请请求来说,根据分配算法会使用 mmap 函数为她分配一块匿名空间,在这个匿名空间里为用户分配空间。
      eg.申请132KB的虚拟内存区域
    addr = mmap(NULL, (size_t)132*1024, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    mmap 函数与 brk 函数的区别  对于小于 128 KB 的请求来说,会在现有的空间中按照堆分配算法(brk、sbrk)为它分配一个堆空间,大于 128 kB 时,就使用 mmap 函数分配一个匿名空间给用户使用。
      简单来说就是两个区别:
      1.一个是在现有的堆空间中分配,一个是在设置了 MAP_ANONYMOUS 属性的匿名空间中分配。
      2.一个是用于申请小空间时使用,一个是在用于申请大空间时使用
    mmap 函数的另一种用法  在栈溢出的利用时,若 system 和 execve 函数都被禁用的时候,我们可以使用 mmap 或者 mprotect 函数将 bss 段的内存权限设置为可执行,这样我们再把 shellcode 写入到里面,接着将 eip 执行他,就可以达到直接执行 shellcode 的效果。
      例如,jarvisoj 的 level5:

    堆入门的必备基础知识

    堆入门的必备基础知识
      WriteUp的链接如下,里面讲到了详细的用法和参数设置。
      https://blog.csdn.net/zszcr/article/details/79703642
      munmap函数原型:
    int munmap(void *start,size_t length)
      eg.删除已经创建的虚拟内存区域
    ret = munmap(addr, (size_t)132*1024);
    分配的过程:

    堆入门的必备基础知识

    堆入门的必备基础知识
    0×03 堆的使用场景
    • new 一个新对象
    • 传参为数组时
    0×03 Bin
    fast bins  small bins
      large bins
      unsorted bin

    fast bins  用于一些较小的 chunk 释放之后发现存在与之相邻的空闲的 chunk 并将它们进行合并
    typedef struct malloc_chunk *mfastbinptr;  /*
      This is in malloc_state.
      /* Fastbins */
      mfastbinptr fastbinsY[ NFASTBINS ];
      */

    参考文章  Libc堆管理机制及漏洞利用技术 (一)
      Heap overflow using unlink
      ctf-wiki
      浅析Linux堆溢出之fastbin
    大家有任何问题可以提问,更多文章可到i春秋论坛阅读哟~专栏  1


    温馨提示:
    1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
    2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
    3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
    论坛交流群:672619046
    微信公众号
    快速回复 返回顶部 返回列表