首页
社区
课程
招聘
[原创]glibc的free函数笔记
2016-8-3 20:29 6007

[原创]glibc的free函数笔记

2016-8-3 20:29
6007
最近自己学习linux的堆利用,网上的文章怎么也看不懂,索性还是自己来吧,所以有了这篇笔记。没有什么技术含量,大牛勿喷
概述:
代码:glibc-2.21
操作系统:Kali-Linux-2016.1-vbox-i686-disk1虚拟机
自己随便写一个用malloc,free的代码就行,然后kali的edb调试器,和源码比较动态跟踪,代码就很好理解了。
代码在malloc.c里。
正文:
首先要介绍libc代码的内存管理的数据结构
struct malloc_chunk {

  INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */
  INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */

  struct malloc_chunk* fd;         /* double links -- used only if free. */
  struct malloc_chunk* bk;

  /* Only used for large blocks: pointer to next larger size.  */
  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  struct malloc_chunk* bk_nextsize;
};
内存布局是这样的
    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |             Size of previous chunk, 如果前一个内存已经释放了| |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |             Size of chunk, in bytes                       |M|P|
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |             User data starts here...                          .
      .                                                               .
      .             (malloc_usable_size() bytes)                      .
      .                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |             Size of chunk                                     |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
当你申请一块内存是,申请的内存大小不仅仅是你要申请的内存,还要有前面的那个结构的大小和对齐等问题。对于32的系统,申请的大小总是以8字节对齐,所以低三位总是为0,系统正好利用这三位当了标志位,你申请的内存malloc函数,只填写malloc_chunk.size变量。
free一个地址p时,从p的开始的8个字节就是malloc_chunk的fd和bk,也并不是释放所有都要用到fd和bk,free函数真正的释放内存操作是_int_free函数,函数的参数是(char*)p-8后的地址,_int_free函数按内存大小和是否chunk_is_mmapped分成以下3种情况;
1.size<=64(64位系统是128,64位系统是32系统的一倍),使用fastbin回收。
2.!chunk_is_mmapped,64<size<=512(small_bin),unlink也是在这个里面被调用的。
3以上都不成立的话调用 munmap_chunk 
所以如果想要unlink的话,内存的大小要大于64才能利用,这里也主要介绍第2种内存释放的情况。释放地址的时候,会合并当前内存前后已经释放的内存,来整理内存碎片,释放的内存地址,就是用前面的fd,bk双向链表来记录的,unnlink就是把和当前地址相邻的已经释放的内存从链表里脱下来。和当前地址整合成一个连续的大地址。内存的高地址为代码中的av->top。合并当前地址的低地址叫后向合并(利用也主要在这里),合并当前地址高地址的空闲地址叫前向合并。
系统是通过malloc_chunk.size中的最低位来判断什么时候进行前向和后向合并的。
为了方便描述,当前的地址记位chunk,它的高地址叫nextchunk,低地址叫prechunk,关系是nextchunk=chunk+chunk->size,prechunk=chunk->pre_chunk;chunk->size是低3位已经被清零了。也是根据size的最低位来确定执行前向合并和后向合并。
后向合并:
释放内存时,会把它的nexchunk->size最低位设置为0。chunk->size的最低位设置为1,也就是说如果一个chunk的size最低位为0。那么它的prechunk已经释放了。调用unlink把prechunk从链表里脱下来。
前向合并:
是nextchunk的nextchunk的size最低位为0是执行前向合并。在执行前向合并时,会先判断nextchunk是不是av->top,如何不是,才判断是否执行前向合并;调用unlink把nextchunk从链表里脱下来。
unlink的利用:
为了能过函数里的检测:最好是触发后向合并里的unlink并且它的nextchunk是av->top这样才不会执行判断链表unsortchunk的操作。
我的想法是:
1.连续申请两个内存大于512的地址。放到指针first,second里。
2.构造假chunk,fd=&first-12,bk=&first-8.假设程序里有溢出漏洞,执行对first拷贝是会溢出。这样就能修改second的chunk了,修改的内容pre_size为second的chunk地址-first地址,chunk->size的最低位为0.
3.执行free(second),是将unlink(first),执行后first里的内容就不是堆地址而是&first-12了。
其实内容还有很多,有图就很好,调试在看一下源代码就很好理解了。

阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

收藏
点赞1
打赏
分享
最新回复 (4)
雪    币: 519
活跃值: (3769)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
龙飞雪 2016-8-4 16:49
2
0
支持一个,不错
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小漆 2016-8-5 18:05
3
0
叼,顶
雪    币: 39
活跃值: (114)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lapulasi 2016-8-8 17:13
4
0
内存布局的图中size的后3个比特有个笔误:
|M|P| 应当是 |N|M|P|
雪    币: 32
活跃值: (10)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
未asd 2017-10-27 12:57
5
0
叼炸天!
游客
登录 | 注册 方可回帖
返回