0-环境

Ubuntu 16
gcc、g++
pwntools
gdb、pwndbg、gdbpeda

环境都无所谓,其余环境可能实际操作与文章相差较大。

1-堆申请(malloc)

并不是申请多少给多少,是系统给了好多供堆使用,然后malloc去里面申请。

1
2
3
4
5
6
7
8
9
10
C
#include<stdio.h>

int main()
{
void *ptr=malloc(0x10);
void *ptr1=malloc(0x90);
void *ptr2=malloc(0x1000);
return 0;
}

调试步骤:

b main 主函数下断
next 看着汇编执行
vmmap 查看内存有无分配heap 此步骤旨在观察 执行malloc指令前后的区别
heap 查看堆
vis 可视化查看堆,目前还不知道这玩意有啥用

此为Ubuntu16环境下正常显示,其中首个 chunck 即为 malloc(0x10)
image-20220118170140860
Ubuntu18下会出现下面这种情况,第一个chunk 的 size 为 0x251
image-20220118170527315
原因为在 Ubuntu18(libc2.26) 及以上中默认加入了 tcache 机制

在Glibc的2.26中 新增了Tcache机制 这是ptmalloc2的缓存机制
Tcache为每个线程都预留了这样一个特殊的bins, bin的数量是64个 每个bin中最多缓存7个chunk。在64位系统上以0x10的字节递增,从24递增到1032字节。32位系统上则从12到512字节,所以Tcache缓存的是非Large Chunk的chunk。

同时Tcache使用两个新的数据结构来管理Tcache中的bin

这玩意儿暂时无用,先跳过,知道是因为这个原因就行。

2-Chunk

chunk由一个结构体定义,但是使用中和空闲时会体现出两种不同的状态。
空闲状态多了 fd、bk、fdnextsize、bknextsize。fd指向下一个被释放的chunk bk指向上一个被释放的chunk
前一个chunk为空时presize位为前一个chunk大小,当前一个chunk不为空时,可以顺延下来使用这个空间。单字节溢出漏洞和这个有关。
chunk头中的size位的低三位中 p 位记录前一个chunk是否被分配

详细看之前写的,这篇是复习就不再写了:https://shangu127.top/2021/10/08/107/#3-chunk

在 64位情况下,使用中的chunk大小计算公式如下:

in_use_size = (用户请求大小 + 16 - 8)align to 8B

加 16 是因为需要存储 prev_size 和 size,但又因为向下一个chunk借了 8位 ,所以要减去9,每分配一个chunk的overhead为 8B ,即 size_sz的大小.(八字节对齐,32位为四字节对齐)

2.1-Prev_size

1、当前一个chunk空闲时存放前一个chunk大小,作用是可以获取前一个chunk的地址,即
前一个chunk地址 = 当前chunk指针 — pre_size

3-堆释放(free)

堆被释放后会根据大小和处于的状态进入相应的bins进行管理。
bins的管理结构就是链表,之前说到的fd和bk,就可以理解为是双链表的头结点和尾结点

3.1-fastbin

默认情况下,SIZE_SZ为 4 B 的平台,小于64B的chunk,8B 就是128B。会首先查找fastbins中是否有所需大小的chunk存在(精确匹配),存在的话直接返回。
实际上,可以理解为是small bins的以下部分cache,相当于管理了smallbins的前七个大小的空闲链表。
就是bins命令出现的冒号前的数字。

fastbin有十个元素的数组,分配到fastbin的chunk的头指针会存放进去。
fastbin 采用的是单链表,瞅着和栈差不多,写一个简单的程序就能看出来。
image-20220118203104121
bins中的顺序就是单链表存储的样子,参考栈结构
image-20220118203203068