堆的基础知识

Posted by Mr.Be1ieVe on Monday, February 3, 2020

get_shell

  • 修改某个函数的got表 为 system 的地址,然后参数准备为binsh 就可以
  • 修改free函数为puts函数,然后某个堆里参数准备为某个函数的got表地址 就可以泄露地址了
  • one_gadget

来源:https://www.anquanke.com/post/id/163971

在 64 位程序中:

malloc(8)

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

1.第一个 16 字节是系统最小分配的内存,也就是说你如果想要申请的内存小于系统最小分配的内存的话,就会按照最小的内存来分配。

  • 在 64 位系统中这个值是 16 个字节,在 32 位系统中是 8 个字节
  • 例如,如果代码中是 malloc(0) 的话,堆管理器也会分配最小内存空间给你

2.第二个 8 字节是 pre size 字段的大小(32 位的为 4 字节) 3.第三个 8 字节为 size 字段的大小(32 位的为 4 字节) 4.最后一个 1 字节是 PREV_INUSE 的值,只有 0 或 1两个值


1.pre size 字段。只有在前面一个堆块是空闲的时候才有指,用来指示前一个堆块的大小。前面一个堆块在使用时,他的值始终为 0 2.size 字段。是用来指示当前堆块的大小的(头部加上 user data 的大小)。但是这个字段的最后三位相当于三个 flag ,有另外的作用。

这三位的作用分别是:

1.NON_MAIN_ARENA     这个堆块是否位于主线程
2.IS_MAPPED          记录当前 chunk 是否是由 mmap 分配的
3.PREV_INUSE         记录前一个 chunk 块是否被分配

这里重点讲解最后一位:用来记录前一个 chunk 块是否被分配,被分配的话这个字段的值为 1,所以经常会在已分配的堆块中的 size 字段中发现值比原来大 1 个字节。

  • 所以前一个堆块的释放与否都和这两个字段(pre_size、size)的值有关,这是因为便于内存的释放操作(free)
  • user data 顾名思义就是用来存放用户数据的。

main arena

就算只申请10字节,内核也会分配132KB堆空间给ptmalloc2,用完内核再分配132KB。因为是主线程分配的,所以这个区域叫做 main arena。

==x/2gx &main_arena==

32位的程序使用 x/32xw addr比较直观一点

64位的程序使用 x/64xw addr

top chunk

堆中第一个堆块,程序以后分配到的内存到要放在他的后面,就如下图的0x5578cbd73110(并且,堆向上生长

image-20200131214332010

FD 指向链表中前一个堆块的指针,该指针指向的是chunk的head

BK 指向链表中后一个堆块的指针,该指针也是指向chunk的head,通过 fd 和 bk 可以将空闲的 chunk 块加入到空闲的 chunk 块链表进行统一管理

FD_nextsize 指向前一个与当前 chunk 大小不同的第一个空闲块,不包含 bin 的头指针。

BK_nextsize 指向后一个与当前 chunk 大小不同的第一个空闲块,不包含 bin 的头指针。一般空闲的 large chunk 在 fd 的遍历顺序中,按照由大到小的顺序排列。这样做可以避免在寻找合适chunk 时挨个遍历。

作者:合天智汇 链接:https://www.jianshu.com/p/5263bdbe92e2 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这里我把第二个和第三个都free了

free 函数和 bins

堆管理器会根据用户已经申请到的内存空间大小进行释放,来决定放入哪类 bins 当作去.

主要的 bins 分为以下几类,重点讲解 fast bin,因为 fast bin 是使用到的最多的一类,也是其中结构最为简单的。

调用 free 函数以后程序做了两件事: 1.清空此堆块的 user data 2.将此堆块的指针存储到 main_arena 中了(或是 fast bin 中)

fast bin

顾名思义,就是为了快速重新分配回内存而存在的一个结构。

fastbin所包含chunk的大小为16 Bytes, 24 Bytes, 32 Bytes, … , 80 Bytes。当分配一块较小的内存(mem<=64 Bytes)时,会首先检查对应大小的fastbin中是否包含未被使用的chunk,如果存在则直接将其从fastbin中移除并返回;否则通过其他方式(剪切top chunk)得到一块符合大小要求的chunk并返回。

fast bin 的特性

1.使用单链表来维护释放的堆块 也就是和上图一样,从main_arena 到 free 第一个块的地方是采用单链表形式进行存储的,若还有 free 掉的堆块,则这个堆块的 fk 指针域就会指针前一个堆块。

如下图所示,此时就是一个单链表结构

image-20200131214423497

2.采用后进先出的方式维护链表(类似于栈的结构) 当程序需要重新 malloc 内存并且需要从fastbin 中挑选堆块时,会选择后面新加入的堆块拿来先进行内存分配

如上图,如果程序重新请求和上面的堆块大小一样时候(malloc),堆管理器就会直接使用 fast bin 里的堆块。

这里的话也就是直接使用第二次释放的这个堆块,然后将这个堆块从链表中移除,接着根据堆块的 fk 指针找到这个堆块,此时 main_arena 就指向了这里。

small bin

顾名思义,这个是一个 small chunk ,满足的内存空间比 fast bin 大一点。

如果程序请求的内存范围不在 fast bin 的范围内,就会考虑small bin。简单点说就是大于 80 Bytes 小于某一个值时,就会选择他。

unsorted bin

当 fast bin、small bin 中的 chunk 都不能满足用户请求 chunk 大小时,堆管理器就会考虑使用 unsorted bin 。它会在分配 large chunk 之前对堆中碎片 chunk 进行合并,以便减少堆中的碎片。

  • unsorted bin 与 fast bin 不同,他使用双向链表对 chunk 进行连接

  • unsorted 的字面意思就是”不可回收”的意思,可以看作将不可回收的垃圾(不满足能够进行内存分配的堆块)都放到这个”垃圾桶”中。

image-20200131215053221

「真诚赞赏,手留余香」

Mr.Be1ieVe's Treasure

真诚赞赏,手留余香

使用微信扫描二维码完成支付