参考文献:https://github.com/DhavalKapil/heap-exploitation
void * _int_malloc (mstate av, size_t bytes)
-
修改bytes,保证对齐之类的
-
若av是NULL(缺少可用的arena),调用
sysmalloc
,使用mmap来分配一个chunk
。若成功,调用alloc_perturb
(memset,设为perturb_byte&0xff),最后返回指针。 -
.
- 如果大小
bytes
在fastbin范围内:- 根据大小算下标,然后得到fastbin数组里大小合适的bin
- 把bin里的第一个chunk删掉,把victim指针指向它(全在REMOVE_FB里面,REMOVE_FB参数名字跟调用时的变量名顺序不一样!!)
- 如果victim是NULL,转到smallbin
- 检查victim的大小是不是真的属于那个fastbin,否则
malloc(): memory corruption (fast)
- 调用
alloc_perturb
并返回指针 [[内部函数#static-void-alloc_perturb-char-p-size_t-n|static void alloc_perturb (char *p, size_t n)
]]
- 如果在smallbin范围内
- 根据大小算下标,然后得到smallbin数组里大小合适的bin。
- 如果此bin中没有chunk,就用下一个。这是通过比较指针
bin
和bin->bk
来检查的。 victim = bin->bk
(bin中的最后一个chunk)。(仅限旧版)如果为 NULL(发生在 初始化期间),则调用malloc_consolidate
并跳过检查不同的bin的完整步骤。- 否则,检查
victim->bk->fd
和victim
是否相等。如果它们不相等,则会抛出错误malloc(): smallbin double linked list corrupted
。 - 为物理相邻的下一个chunk设置 PREV_INSUSE bit。
- 从bin list中删除此chunk。
- 根据
av
设置此chunk的适当arena bit。 - 调用
alloc_perturb
,然后返回指针。
- 如果大小不在smallbin范围内:
- 根据请求大小,在largebin数组中获取适当的bin,赋值给idx。
- 检查av→have_fastchunks。如果是1,在av上调用malloc_consolidate。 have_fastchunks
- 如果大小
-
如果尚未返回指针,则表示出现以下一种或多种情况:
- 大小属于“fastbin”范围,但没有可用的fastchunk。
- 大小属于“smallbin”范围,但没有可用的smallchunk(在初始化期间调用malloc_contegrate)。
- 大小属于“largbin”范围。
-
然后,检查unsorted chunks,并将已遍历的数据块放入bin。这是唯一一个将chunk放入bin的地方。从尾部开始遍历unsorted bin。
- victim 指向当前正在处理的chunk。
- 检查 victim 的块大小是否在最小(
2*SIZE_SZ
)和最大(av→system_mem)范围内。否则抛出错误malloc(): memory corruption
。 corruption: 腐败;贪污;贿赂;腐蚀;受贿;(单词或短语的)变体;使人堕落的行为 - 如果(请求的数据块大小在 smallbin 范围内)且(victim是Last remainder chunk)且(它是unsorted bin 中唯一的chunk)且(chunk size >= 请求的cshunk size): 将chunk分成两个:
- 第一个chunk与请求的大小一致,并返回。
- 剩余的chunk成为last remainder chunk。它将被插回unsorted bin。
- 为两个数据块设置适当的 “chunk_size “和 “chunk_prev_size “字段。
- 调用
alloc_perturb
后返回第一个数据块。
- 不满足上面的条件时,从unsorted bin中移除
victim
。如果victim
的大小等于请求的大小,则调用alloc_perturb
后返回victom。 - 如果
victim
的大小在smallbin范围内,则在合适的smallbin头部添加该chunk。 - 否则,在保持排序顺序的情况下,插入到相应的 largebin 中:
- 首先检查最后一个chunk(最小的)。如果
victim
比最后一个chunk小,就把它插入最后一个。 - 否则,循环查找大小 >=
victim
的chunk。如果大小完全相同,则始终插入第二个位置。
- 首先检查最后一个chunk(最小的)。如果
- 整个步骤最多重复
MAX_ITERS
(10000) 次,或者直到unsorted bin中的所有chunk都用完为止。
-
检查unsorted bin后,如果检查请求的大小不在 smallbin 范围内,则检查 largebin。
- 根据请求的大小,获取 largebin 数组的索引,以访问相应的 bin。(用的是上面的idx)
- 如果最大chunk(bin 中的第一个数据块)的大小大于请求的大小,则
- 从尾部开始迭代,找到最小的,大小>=请求大小的数据块,赋值给victim。
- 调用
unlink
从bin中删除victim
chunk。 - 计算
victim
chunk的remainder_size
(即victim
’s chunk size - requested size)。 - 如果
remainder_size
>=MINSIZE
(最小chunk大小,包括头部),则将chunk分割成两个。否则,将返回整个 “victim” chunk。将剩余的chunk插入unsorted bin(尾部)。在unsorted bin中检查unsorted_chunks(av)->fd->bk == unsorted_chunks(av)
。否则就会产生错误(malloc(): corrupted unsorted chunks)。 - 调用
alloc_perturb
后返回victim
块。
-
目前为止,我们已经检查了unsorted 以及 fast, small or large bin. 注意一个单独的bin (fast or small) 是通过 精确地 请求chunk的大小来检查的. 接下来,重复一下步骤直到所有bin 都被用完:
- idx++.(很久很久以前,它被设置为了请求大小对应的bin, small或者large)(到现在没有返回只能说明这个bin是空的(?))
- 使用
av->binmap
map 来跳过空bin. victim
指向当前bin的尾部.- 上两步使用binmap来保证:跳过的bin绝对是空的。但是它不能保证所有的空bin都被跳过了。 所以要再检查一遍。跳过空的。(continue),直到一个非空bin。
- 切开牺牲品(victim) (
victim
非空bin的最后一块)(切成两块)(除非剩得太少). 剩余chunk插进unsorted bin (尾部). 插入前有一个检查unsorted_chunks(av)->fd->bk == unsorted_chunks(av)
. 失败时抛出”malloc(): corrupted unsorted chunks 2”. - 调用
alloc_perturb
并返回victim
.
-
如果到这儿还没找到bin,就用top chunk //Top chunk
victim
指向av->top
.- 如果 ‘top’ chunk 大小 >= ‘请求大小’ +
MINSIZE
, 分裂,剩余部分变成新的top chunk,调用alloc_perturb
并返回前面的chunk. - 检查av→have_fastchunks。如果是1,在av上调用malloc_consolidate。返回第5步。
- 调用
sysmalloc
,alloc_perturb
, 返回.
__libc_malloc (size_t bytes)
- 调用
arena_get
得到一个mstate
指针. - 用上面的指针和bytes调用
_int_malloc
. - 解锁arena.
- 返回之前有个断言,要求满足下面条件中的至少一个:
- Returned pointer is NULL
- Chunk is MMAPPED
- Arena for chunk is the same as the one found in 1.
_int_free (mstate av, mchunkptr p, int have_lock)
-
p + chunksize(p)
是否超出了内存的最大地址 .超过则抛出 “free(): invalid pointer” -
检查chunk的大小是否至少为
MINSIZE
、是否是MALLOC_ALIGNMENT
的倍数。有一样不符合则会引发错误(“free(): invalid size”)。 -
如果chunk的大小在fastbin范围:
- 检查下一个chunk的大小是否在最小值和最大值(
av->system_mem
)之间,否则引发错误(“free(): invalid next size (fast)”)。 - 在chunk上调用
free_perturb
函数。 - 为
av
设置FASTCHUNKS_BIT
为true。 - 根据chunk大小获取fastbin数组的索引。
- 检查快速bin中的顶部是不是要添加的chunk,不是则引发错误(“double free or corruption (fasttop)”)。
- 检查快速bin顶部的chunk大小是否与要添加的chunk大小相同,不相同则引发错误(“invalid fastbin entry (free)”)。
- 将chunk插入fastbin的顶部并返回。
- 检查下一个chunk的大小是否在最小值和最大值(
-
如果chunk不是mmapped:
- 检查chunk是否为top chunk。如果是top chunk,引发错误(“double free or corruption (top)”)。
- 检查下一个chunk(按内存顺序)是否在arena的边界内。如果不在边界内,引发错误(“double free or corruption (out)”)。
- 检查下一个chunk(按内存顺序)的前置使用位是否被标记为未使用。如果未使用,引发错误(“double free or corruption (!prev)”)。
- 检查下一个chunk的大小是否在最小值和最大值(
av->system_mem
)之间。如果不在范围内,引发错误(“free(): invalid next size (normal)”)。 - 在chunk上调用
free_perturb
函数。 - 如果前一个chunk(按内存顺序)未被使用,调用
unlink
函数解除前一个chunk的链接。并且把当前指针指向它,更新size变量。 - 如果下一个chunk(按内存顺序)不是top chunk:
- 如果下一个chunk未被使用,调用
unlink
函数解除下一个chunk的链接。 - 合并chunk与前一个和下一个(按内存顺序)chunk,如果有任何一个是自由的,并将其添加到未排序bin的头部。在插入之前,检查
unsorted_chunks(av)->fd->bk == unsorted_chunks(av)
是否成立,如果不成立,引发错误(“free(): corrupted unsorted chunks”)。
- 如果下一个chunk未被使用,调用
- 如果下一个chunk(按内存顺序)是top chunk,则将这些chunk适当合并成一个单独的top chunk。
-
如果chunk是映射的(mmapped),则调用
munmap_chunk
函数。
__libc_free (void *mem)
- Return if
mem
is NULL. - If the corresponding chunk is mmapped, call
munmap_chunk
if the dynamic brk/mmap threshold needs adjusting. - Get arena pointer for that corresponding chunk.
- Call
_int_free
.