unlink主要利用从双向链表中取出chunk时的操作,通过伪造fd和bk指向伪造的位置,触发后达成利用的一种手法。
下面是双向链表中取chunk的操作过程
当然,那是没保护情况,现在早就上保护了
// 由于 P 已经在双向链表中(已经被free),所以有两个地方记录其大小,所以检查一下其大小是否一致(size检查)
if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0)) \
malloc_printerr ("corrupted size vs. prev_size"); \
// 检查 fd 和 bk 指针(双向链表完整性检查)
if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) \
malloc_printerr (check_action, "corrupted double-linked list", P, AV); \
// largebin 中 next_size 双向链表完整性检查
if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0) \
|| __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0)) \
malloc_printerr (check_action, \
"corrupted double-linked list (not small)", \
P, AV);
针对双向链表完整性检查,为了通过验证,我们需要(32位为例)
fakeFD -> bk == P <=> *(fakeFD + 12) == P
fakeBK -> fd == P <=> *(fakeBK + 8) == P
满足时将进行
fakeFD -> bk = fakeBK <=> *(fakeFD + 12) = fakeBK
fakeBK -> fd = fakeFD <=> *(fakeBK + 8) = fakeFD
将其指向同一指向P的地址时,P 的指针将指向了比自己低 12 的地址处。
*P = P - 8
*P = P - 12