FASTBIN 利用方法(更新中~咕)
Last Update:
FASTBIN 利用方法(更新中~咕)
fastbin采用一个单向链表来维护释放的堆块。我们先来看一下释放堆块源码中逻辑上的关键部分
1 | |
为了不在这里介绍一些很长的判断,我选择将源码中的注释放了过来。fastbin (av, idx)是一个宏的调用,实现如下:
1 | |
不难发现它根据传入的分配区,和idx变量(根据释放堆块的大小判断出应放入fastbinsY的下标)返回了这一堆块该放入的fastbinsY的地址,之后进行如下操作P->FD = *FB; *FB = P;。
用叙述性的语言表达出来的话就是,fastbinsY[idx]中存着最后链入其中的堆块的地址。在最初时这个值为0。当有新的堆块链入时,他会把这一地址写入新来的堆块的fd中。同时将fastbinsY[idx]更新为新的堆块的地址。
打一个可能没那么形象的比方,向FASTBIN中插入堆块就像是排队,队尾的人会举着一个标记队尾的牌子,当有新的人来排队时,新来的人会跟在队尾后面,接过前队尾传来的牌子。(之所以说不太形象大概是因为fastbin是后进先出,显然排队讲究先进先出)。
double free
简单理解fastbin的结构之后我们来看double free。double free的利用场景通常是程序在释放内存时没有检查堆块是否已经被释放。因此我们可以将一个已经放入fastbin的堆块再次free。
但在free中对这种行为并不是没有任何检查。如下为2.23版本的free函数
1 | |
这里检查了四件事:
1,free的堆块是不是fastbin的头堆块(即最后一个放入fastbin的堆块)
2,free的堆块是不是arena中的top chunk。
3,free的堆块的nextchunk(这里的nextchunk指物理相邻的chunk)是否超过了topchunk的边界。
这里使用了nextchunk这一变量来源如下:
1 | |
顾名思义是根据堆块大小偏移获取nextchunk的地址,如果nextchunk的地址超过了topchunk则报错。
4,最后检查nextchunk中是否将prev_inuse置1。
由于上述条件的存在,我们可以得出一些堆利用中应该注意的点。
1 | |
所以我们在进行double free的利用时通常如下:
1 | |
收益
经过double free之后我们的收益是什么?经过double free我们的chunk1被放入了fastbin中2次,我们先申请出来一个,我们就能获得操作一个还在fastbin中的chunk的机会。
例如我们修改它的FD指向我们想要修改的地址,如hook等,当我们第二次申请chunk1时,它便会将fd中的内容写入fastbin的头(fb = p->fd)。我们再次申请堆块时,新申请的堆块地址就是我们写入的地址。