基于ctfwiki中Tcache attack的一篇博客
本文目的:在阅读 wiki 中的 Tcache attack 中,发现了不少模糊不清的定义和表述,于是写了这篇博客,若有问题请联系本人邮箱,感谢ing。
1. Tcache overview
在 tcache 中新增了两个结构体,分别是 tcache_entry 和 tcache_perthread_struct:
typedef struct tcache_entry |
tcache_entry:Tcache 链表中的一个空闲内存块(chunk)。
tcache_perthread_struct:每个线程在堆上维护的管理结构,记录了当前线程所有 Tcache 的状态。
其中有两个重要的函数,tcache_get() 和 tcache_put():
static void tcache_put (mchunkptr chunk, size_t tc_idx) |
这两个函数会在函数 _int_free 和 _libc_malloc 的开头被调用,其中 tcache_put 当所请求的分配大小不大于 0x408 并且当给定大小的 tcache bin 未满时调用。
一个 tcache bin 中的最大块数 mp.tcache_count 是 7。
/* This is another arbitrary limit, which tunables can change. Each |
在 tcache_get 中,仅仅检查了 tc_idx。此外,我们可以将 tcache 当作一个类似于 fastbin 的单独链表,只是它的 check 并没有 fastbin 那么复杂,仅仅检查 tcache->entries[tc_idx] = e->next;。
2. Tcache Usage
内存释放:
在 free 函数的处理流程初期,程序在完成对齐性与堆块状态的前置检查后,会优先将符合条件的 chunk 回收到 Tcache 中。
_int_free (mstate av, mchunkptr p, int have_lock) |
内存申请:
在内存分配的 malloc 函数中有多处,会将内存块移入 tcache 中。
a. 针对 Fastbin:
当申请的内存符合 Fastbin 大小且命中可用空闲块时,系统会将该 Fastbin 链上的其余空闲块批量迁移至对应的 Tcache 中。
b. 针对 Smallbin:
当申请的内存属于 Smallbin 范围并在链中找到匹配项时,系统会顺便将该 Smallbin 链上的其他空闲块填入 Tcache。
c. 针对 Unsorted Bin:
在遍历 Unsorted Bin 链时,即使找到大小精确匹配的 chunk,系统也不会立即返回,而是先将其放入 Tcache 并继续遍历。
符合 fastbin 的时候:
if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ())) |
直接命中 (Direct Hit):
tcache 取出:在内存分配的入口阶段,系统会首先根据申请尺寸判断对应的 Tcache bin 中是否存在可用空闲块。若命中缓存,则直接从中摘取并返回;否则,程序将进入 _int_malloc 执行后续的分配逻辑。
填充后取出 (Stash-and-Get):
Unsorted Bin 阈值控制:在循环处理 Unsorted Bin 链表时,若移入 Tcache 的 chunk 数量达到了设定的最大阈值(由 mp_.tcache_unsorted_limit 控制),分配流程将立即终止并返回。该阈值默认设置为 0,表示对处理数量不设上限。
|
Unsorted Bin 处理结束返回:在循环处理 unsorted bin 内存块后,如果之前曾放入过 tcache 块,则会取出一个并返回。
|
后续实例会在学习完wiki上所有的堆攻击内容后一并补充,
