【Pwn】堆学习之glibc2.31下的tcache机制
0x2 tcache机制
0x1 tcache是什么
· tcache是满足一定条件的chunk被free后首先进入的bin,在2.31版本中一个tcachebin最多存储7个chunk,使用单链表,头插法。在64位系统下,不同的tcachebin可存储的chunk的大小范围如下:idx0对应0-24字节,idx1对应25-40字节,idx2对应41-56字节。
0x2 chunk进入tcache的变化
· chunk进入tcache后,user_data的前两个槽位会发生变化。user_data+0x00写为next,指向tcache链表中的下一个chunk,如果链表为空则next也为null;user_data+0x08写为key,指向当前线程的tcache,标志当前chunk位于tcache链表中,也用于辅助double free检测。当前bin的头节点会指向新进入的chunk。注意:chunk进入tcache链表时并不是整个chunk在内存空间中移动,而是user_data的前两个槽位发生变化。chunk进入tcache的逻辑由tcache_put函数负责。
0x3 chunk离开tcache的变化
· chunk离开时,当前bin头节点指向next,即下一个chunk的user_data头。key被清空,标志chunk被使用。
0x4 tcache实例
· 使用如下实例:
#include <stdio.h>
#include <stdlib.h>
int main() {
setbuf(stdout, NULL);
char *a = malloc(0x20);
char *b = malloc(0x20);
printf("a = %p\n", a);
printf("b = %p\n", b);
free(a);
free(b);
char *c = malloc(0x20);
char *d = malloc(0x20);
printf("c = %p\n", c);
printf("d = %p\n", d);
return 0;
}
· 两次malloc后chunk状态:

· free(a)后:

可以看到a确实进入了tcache。

可以看到user_data+0x08变成了指针一样的东西,即key,指向tcache。
· free(b)后:

可以看到a与b此时都在tcache中,b的user_data的前两个槽位也都变成了指针,其中user_data+0x00变为next,指向a的user_date,user_data+0x08变为key,指向tcache。此时a与b的位置状态如下:
head-->b-->a-->NULL
· char *c = malloc(0x20)后:

可以看到b已经从链表中弹出,且key被清除,标志该chunk已离开链表。
· tcache被塞满的情况(使用如下实例):
#include <stdio.h>
#include <stdlib.h>
int main() {
setbuf(stdout, NULL);
char *a = malloc(0x20);
char *b = malloc(0x20);
char *c = malloc(0x20);
char *d = malloc(0x20);
char *e = malloc(0x20);
char *f = malloc(0x20);
char *g = malloc(0x20);
char *h = malloc(0x20);
free(a);
free(b);
free(c);
free(d);
free(e);
free(f);
free(g);
free(h);
return 0;
}
· 8次free后:

可以看到存储0x30大小的tcachebin被填满,最多存储7个chunk,第8个chunk进入fastbin。

浙公网安备 33010602011771号