欢迎来到HDUISA wiki,如果这是你的第一次到来,请点击此处注册

前言

先说下,这个堆不是指的二叉堆,在这片文章中,我将拓展一下堆的概念,其实准确的来讲我们是在研究动态内存管理。这个思想在操作系统领域早在1993年或更早以前就已经存在。

这是我能找到的最早的windows的可考的关于堆设计的文章

在这片文章中提到,堆是为了更好的方便创建程序的动态数据结构。事实上,不只是在操作系统领域,在一些对于性能要求高的软件场景中,它们也都会有一些自己定制的内存管理操作(比如PHP,Chrome等),这些管理方法大多有自己的优缺点,但毫无疑问,他们都是为了让自己的程序跑的效率更高。

为什么要研究这个?

程序漏洞,特别是发生在动态分配的内存上的,诸如溢出,逻辑错误等等。这些bug往往不能直接控制程序流,但在适当构造后,我们可以攻破内存管理系统,利用这个系统来达成我们的目的。

接下来我会主要介绍下glibc内存管理方法,以及介绍一些攻击方法。

case study

Linux glibc heap internals

概览

glibc的堆管理其实比较简单,堆块的创建主要使用mallocrealloccalloc。对于所有通过这些api动态分配在堆上的块称作chunk

    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of previous chunk, if unallocated (P clear)  |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of chunk, in bytes                     |A|M|P|
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             User data starts here...                          .
            .                                                               .
            .             (malloc_usable_size() bytes)                      .
            .                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             (size of chunk, but used for application data)    |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of next chunk, in bytes                |A|0|1|
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

一旦它们被free,会依据其chunk的大小被放到相应的bin,可以把bin理解成回收器,bin又分为4种fastbinsmall binunsorted binlarge bin

其中大小关系:fastbin < small bin < large bin.

unsorted bin比较特殊,这个等会再说。

现在我们有这么多bin,总要找个地方放吧?这个地方被称为arena,保存着管理一个堆的所有信息。每个程序启动时都会初始化一个main arena,在之后扩容,或者多线程情况下,会出现第二,第三个arena。。。

这就是glibc的大致情况,怎么样,简单吗?可以告诉你的是,一点都不简单

其实

首先要搞清楚的是bin是什么。要搞清楚这个问题,得先看看arena的定义:

1678   struct malloc_state
1679   {
1680      /* Serialize access.  */
1681      __libc_lock_define (, mutex);
1682
1683      /* Flags (formerly in max_fast).  */
1684      int flags;
1685
1686      /* Fastbins */
1687      mfastbinptr fastbinsY[NFASTBINS];
1688
1689      /* Base of the topmost chunk -- not otherwise kept in a bin */
1690      mchunkptr top;
1691
1692      /* The remainder from the most recent split of a small request */
1693      mchunkptr last_remainder;
1694
1695      /* Normal bins packed as described above */
1696      mchunkptr bins[NBINS * 2 - 2];
1697
1698      /* Bitmap of bins */
1699      unsigned int binmap[BINMAPSIZE];
1700
1701      /* Linked list */
1702      struct malloc_state *next;
1703
1704      /* Linked list for free arenas.  Access to this field is serialized
1705         by free_list_lock in arena.c.  */
1706      struct malloc_state *next_free;
1707
1708      /* Number of threads attached to this arena.  0 if the arena is on
1709         the free list.  Access to this field is serialized by
1710         free_list_lock in arena.c.  */
1711      INTERNAL_SIZE_T attached_threads;
1712
1713      /* Memory allocated from the system in this arena.  */
1714      INTERNAL_SIZE_T system_mem;
1715      INTERNAL_SIZE_T max_system_mem;
1716    };

可以看到fastbin就是mfastbinptr 类型的一个数组(1686)

bins也就是我们说的small bin,large bin….

值得一提的是有个叫top和last_remainder的东西,先不管

看看fastbin:

typedef struct malloc_chunk *mfastbinptr;

1067    struct malloc_chunk {
1068
1069      INTERNAL_SIZE_T      mchunk_prev_size;  /* Size of previous chunk (if free).  */
1070      INTERNAL_SIZE_T      mchunk_size;       /* Size in bytes, including overhead. */
1071
1072      struct malloc_chunk* fd;         /* double links -- used only if free. */
1073      struct malloc_chunk* bk;
1074
1075      /* Only used for large blocks: pointer to next larger size.  */
1076      struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
1077      struct malloc_chunk* bk_nextsize;
1078    };
1079

可以看到,其实fastbin就是malloc_chunk*的别名,看到那一堆fd和bk了吗?fastbin只使用其中的fd指针,也就是fastbin其实是单链表。作用从名字就能看出来,fastbin当然是为了fast!

来看看bins

typedef struct malloc_chunk* mchunkptr;

??感情都是malloc_chunk吗。是的,仔细想一想,垃圾回收就是回收chunk,干嘛要改原来的结构体呢

small bin: 相比较fastbin多用了一个bk指针,还是从字义上理解,small当然就是emmm,好像没啥。这里需要提一下的是基本上日常使用大多数chunk都是fastbin或者smallbin,因为largebin确实很large。

large bin: 最大的bin,对它处理也有一些特殊的地方可以利用,它拥有chunk里面的所有fd bk指针

然后是每个bin的size范围。我们得分32位和64位2种情况。这里我们一致采用32位进行讨论:

fastbin:

DEFAULT_MXFAST             64 (for 32bit), 128 (for 64bit)

small bin:

size between fastbin and large bin

large bin:

size > 65536

再然后我们得搞清楚堆块的内存布局:

chunk(in use):

#------------------------#
|prevsize  |  (size|flag)|
|userdate  |   ...       |
| ...      |   ...       |
...

chunk(freed):

1. fastbin
#------------------------#
|prevsize  |  (size|flag)|
|fd        |   ...       |
| ...      |   ...       |

如果没有其他同size的被free的fastbin的话fd就是0

2. smallbin
#------------------------#
|prevsize  |  (size|flag)|
|fd        |   bk        |
| ...      |   ...       |

如果没有其他同size的被free的smallbin的话fd和bk都指向&bins,也就是一个双向循环链表

3. largebin
#------------------------#
|prevsize    |  (size|flag)  |
|fd          |   bk          |
|fd_nextsize |   bk_nextsize |


如何欣赏glibc源码

没法欣赏。

堆管理主要的部分在malloc.c及arena.c

free的入口是libc_free

malloc的入口是libc_malloc

只能说这么多了,剩下的得自己体会,glibc的代码其实还是比较好懂的,不需要什么额外的知识

强烈建议自己看看glibc代码,把所有应该用自己看代码来学习的部分放这里我觉得不好,我也不会那么干。学会如何看别人的代码真的是一个非常重要的素养,哪怕这代码写的不怎么样,说多了都是泪。。。

放上一个网址

https://code.woboq.org/userspace/glibc/malloc/malloc.c.html

一些技巧

some pic link

UAF

todo

todo

fastbin attack

glibc malloc学习笔记之fastbin 堆溢出学习之0CTF 2017 Babyheap

unsortbin attack

todo

shrink chunk

todo

extend chunk

todo

house of force

todo

house of mind

todo

free_hook & malloc_hook & realloc_hook

堆溢出学习之0CTF 2017 Babyheap

house of orange

todo

Windows10 heap internals

win10 heap = NT heap + Segment heap

wait for your editing

可以先看这个

打印/导出