初学unlink
unlink是我学的第二个堆溢出的知识点,在这之前沉淀了好久的堆概念,非常的混乱,不过好在终于整理的差不多了。
先讲讲malloc和free的运作流程,这也是探究了最久的一个概念,关于heap的结构就不说了。
malloc流程:
1.如果处于mmap的范围,直接调用mmap分配
2.如果所需分配内存在fastbin的范围里会在fastbin里查找空闲的chunk,如找到则结束。
3.如果所需分配的内存在smallbin的范围里,就去smallbin里查找,如找到则结束。
4.如果所需分配的内存不在smallbin里,那么就会先合并fastbin里的chunk(注意合并条件需要chunk相邻)并放入到unsorted bin准备接下去的工作
5.在unsorted bin里查找last_remainder是否大于等于所需分配内存的chunk,如果有大于的,就将其分割出来使用,剩下的称为last_remainder,如果有刚好的大小chunk,则会直接将其使用;如果last_remainder小于所需分配内存的chunk,就会先把此chunk放入 small/large bin 中去,然后去遍历其他在unsortedbin里的chunk,如果有大于的,就将其分割出来使用,其chunk剩下的部分称为last_remainder,如果有刚好的大小chunk,则会直接将其使用,如果此chunk小于所需分配内存,就会先把此chunk放入 small/large bin 中去,接着再重复循环下一个chunk(注意,放入small/large bin的时候还会再判断合并一次)
6.在small bin和large bin中搜索最合适的chunk(不一定是精确大小,如果是大于的话则会进行切块操作,切下剩余的会被放入unsortedbin里当作last_remainder)
7.使用topchunk分配
8.将topchunk放入unsortedbin里,进行内存块申请,分配新的topchunk,然后再由topchunk分配(这种情况下一般是topchunk已经被多次分配而导致变为很小了,所以需要重新申请一块topchunk)
同一个bin里malloc分配查找chunk会从fd指针链的开头开始查找
free流程:
1.如果free的空间是由mmap分配的,则直接归还操作系统
2.如果free的chunk在fastbin的范围内,放入fast bin,结束(以下合并操作不会进行)
4.如果后一个chunk是top chunk,则将当前chunk(经过步骤2的合并也一样会)并入top chunk
5.如果后一个chunk时free的(并且不是fastbin里的),将后面的chunk合并,并且将两个chunk的size相加覆盖两个chunk中低地址的chunk的size以及修改低地址的chunk的fd和bk指针。然后放入unsorted bin,执行unlink
6.前后chunk都不是free的,放入unsorted bin
free之后的chunk第一时间只会进入unsortedbin或者fastbin,直到malloc之后才可能会进入到smallbin或其他bin
fastbin的chunk的下一个chunk的prev_size始终为1,也就是说fastbin里chunk始终不会合并
假设free(a);free(c);free(e); 则在非fastbin里的fd指针是e->c->a->main_arena,bk是a->c->e->main_arena
unlink
那先来介绍一下unlink,啥是unlink呢
unlink就是从bin中摘除一个块的操作,而主要的过程就是摘除时会将前后的chunk的fd、bk指针设置好
unlink一般发生在free函数当中,也就是他是free函数中的一个步骤,他会在free某一个块的时候,如果这个块附近有freechunk,那么他就会合并,并且把这个合并完之后的chunk摘除,然后当作一个新的freechunk加入到unsortedbin里,举个例子
这是一个free了两个chunk的unsortbin(请注意,这里的0x7f88e8344b78是unsortbin的头,也有fd和bk指针,fd指针指向0x11ac600,bk指针指向0x11ac440,所以形成一个循环)
假设我此时free了一个和上图两个物理不相邻的chunk,也就是不会导致合并,就会把这个新的freechunk的fd指针指向0x11ac600,bk指向0x7f88e8344b78,然后再修改0x11ac600的bk指针为这个新的freechunk
这都是一些很正常的操作
但是如果我free了一个和上图某一个chunk物理相邻的chunk,就假设是0x11ac600的相邻chunk把,假设我释放了一个地址为0x11ac500的chunk,此时0x11ac6000的bk和fd指针都不为空(unlink需要的条件,实际上,只要unsortbin里有一个chunk,那这个chunk的fd和bk都不为空),那么就会先将其合并,然后将0x7f88e8344b78的fd指针指向0x11ac440,再将0x11ac440的bk指针指向0x7f88e8344b78,也就是摘除0x11ac600,接着因为新freechunk的规则,将0x11ac500的fd指针指向0x11ac440,然后bk指针指向0x7f88e8344b78,然后再将0x11ac440的bk指针指向这个新freechunk:0x11ac500。
刚刚说的第二种情况就是unlink的情况,他会在让处于unsortbin里中间(即bk和fd指针不为空,也就是unsortbin里的任意chunk)的chunk与其他chunk合并的时候被摘除,然后将合并完后的chunk放入unsortbin链表尾部。
在free函数里的unlink的目的很简单,就是为了将合并完后的chunk放入unsortbin链表而已,但是在其他地方可能就只有摘除块的作用而已
接下来看个例题
2014 HITCON stkof
这个题目有几个函数,依旧是常见的创建,删除,修改
我比较懒,就只针对这篇文章做出几个修改和精进以及说明
首先是这个检查部分,其实这些都是没什么问题的,为下面的fake_chunk部分铺路
我一开始看到这个的时候,就很疑惑,这个next_prev设置成0x20为什么能绕过检测,最后知道了之后,我感觉作者在这里搞得有点复杂了
其实就是检测1和检测2,但是他没有说清楚而已,实际上是这样的:
free chunk3的时候 他首先判断了chunk3的PREV_INUSE位是否为0,发现为0,于是依据chunk3的pre_size,得到上一个chunk(也就是得到fake chunk),然后就会去检查这个fake_chunk的size(0x20)和对应的下一个chunk的pre_size(也就是那个next_prev:0x20)是否相等 发现确实相等 于是将fake chunk和chunk3合并,在以上的过程中,没有用到next_size,所以随便用字符串占位就好。
但是通过刚刚的解释,我们其实可以发现,不一定要在pre_size那里写上0x20才可以绕过检测嘛,我直接把fakechunk的size改成0x30不就好了,然后pre_size和nxt_size这两个都不用设置,于是我真的去试了一下,确实也可以,所以我说作者搞复杂了。
还有一个要说明的就是这个
这里可能有人看不懂,其实就是因为
这里更改了0x602140的fd和bk指针,所以才变化的。
剩下的也蛮简单的了,应该跟着那篇文章来就没问题,还有不懂的可以跟我交流。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)