zoukankan      html  css  js  c++  java
  • Windwos堆管理体系以及溢出利用

    《0day安全》学习笔记,主要讨论WIndows2000~WIndowsSP1平台的堆管理策略。

    0X01 堆与栈的区别

    栈空间是在程序设计时已经规定好怎么使用,使用多少内存空间。典型的栈变量包括函数内部的普通变量、数组等。栈变量在使用的时候不需要额外的申请操作,系统栈会根据函数中的变量声明自动在函数栈中给其预留空间。栈空间由系统维护,它的分配和回收都由系统来完成,最终达到栈平衡。所有这些对程序员都是透明的。

    堆具备以下特性:

    1.堆是程序运行时动态分配的内存。所谓动态是指所需内存的大小在程序设计时不能预先决定的,需要在程序运行时参考用户的反馈。

    2.堆在使用时需要程序员使用专用的函数进行申请,如C语言中的malloc等函数、C++中的new函数等都是最常见的分配堆内存的函数。堆内存申请有可能成功,也有可能失败,这与申请内存的大小、机器性能和当前运行环境有关。

    3.一般用一个堆指针来使用申请的内存,读、写、释放都是通过这个指针来完成。

    4.使用完毕后要通过堆释放函数进行回收这片内存,否则会造成内存泄漏。如free,delete等。

     

     

    0X02堆的数据结构与管理策略

    对于管理系统来说,响应程序的内存使用申请就意味着要在“杂乱”的堆区中辨别哪些内存是正在被使用的,哪些内存是空闲的,并最终“寻找”到一片“恰当”的空闲内存区域,以指针形式返回给程序。

     

    堆块:堆区额内存按不同大小组织成块,以堆块为单位进行标识,而不是传统的按字节标识。一个堆块包括两个部分:块首和块身。块首是一个堆块头部的几个字节,用来标识这个块首自身的信息,例如,大小、空闲或占用。块身是紧跟在块首后面的部分,也是最终分配给用户使用的数据区。

    注意:块管理系统返回的指针一般是块身的起始位置,连续申请内存就是发现返回的内存之间存在“空隙”,那就是块首。

     

    堆表:堆表一般位于堆区的起始位置,用于检索堆区中所有堆块的总要信息,包括堆块的位置、堆块的大小、空闲或占用等。 堆表的数据结构决定了整个堆区的组织方式。堆表往往不知一种数据结构:如平衡二叉树等。

    堆的内存组织如图所示:

    Windows中占用态的堆被使用它的程序管理,堆表只是管理空闲态的堆块。

    其中最重要的堆表有两种:空闲双向链表Freelist空表)以及快速单项链表Lookaside快表

     

    空表:
    空闲堆块块首包含一对指针,这对指针把空闲堆块组织成双向链表。按照堆块大小的不同,空表总共被分成128条。

    堆区一开始的堆表区中有一个128项的指针数组,被称作空表索引。该数组每一项包含两个指针,用于标识一条空表。

    比如空表的第二项free[1]标识了项中所有大小为8字节的空闲堆块,之后每隔索引指示的空闲堆块递增8字节,free[2]标识16字节,free[3]标识24字节空闲堆块,free[127]标识1016字节空闲堆块。

                            空闲堆块大小 = 索引项 * 8字节

     

    把空闲堆块链入不同的空表,可以方便管理。空表第一项free[0]链入所有大于等于1024字节的堆块(小于512K)。这些堆块按照各自的大小在零号空表中升序排列。

     

     

     

    快表

    快表是Windows用来加速分配而采用的一种堆表。这类单向链表中不会发生堆块合并(其中空闲堆块块首置为占用态)。

    快表也有128条,组织结构与空表类似,只是堆块按单链表组织,而且每条快表最多只有4个节点。

     

    0X03  堆的操作

    堆得操作分为:堆的分配、堆得释放、堆得合并。分配与释放是由程序执行的,堆的合并是由堆管理系统自动完成的。

     

    1.堆的分配

    堆分配分三类:快表分配,普通表分配,零号空表(free[0])分配。

     

    从快表分配:寻找大小到大小匹配的空闲堆块、将其状态修改为占用态、把它从堆表中卸下,最后返回一个指向堆块块身的指针给程序使用。

     

    普通表分配:首先寻找最优的空闲块分配,若失败,则寻找次优的空闲块分配。

    零号空表分配:按照大小升序链着大小不同的空闲块,找最优结果。

    注意:当空表中找不到最优的堆块时,会发生次优分配,即从大块按照请求的大小精确割出一块进行分配,然后给剩下部分重新标注块首,链入空表。

     

    2.堆块释放

    将堆块状态改为空闲,链入相应的堆表。所有的释放块都链入堆表的末尾。

    3.堆块合并

    经过反复的申请与释放,堆区产生很多内存碎片。堆管理系统发现两个空闲堆块彼此相邻,就会进行堆块合并。 包括将两个块从空闲链表中卸下、合并堆块、调整合并后大块的块首信息、将新块重新链入空闲链表。

     

    几个注意点:

    1.快表空闲块被置为占用态,所以不会发生堆块合并操作。

    2.快表只有精确分配时才会分配。

    3.分配与失败有限使用快表,失败用空表。

     

     

    0X04   DWORD SHOOT 堆溢出利用原理

     

    堆溢出的利用的精髓就是精心构造的数据溢出下一个堆块的块首,改写块首的前向指针和后向指针,然后在分配、释放、合并等操作发生时获得一次向内存任意地址读写任意数据的机会。

    原理:

     

    Int remove(ListNode * node)
    
    {
    
        node->blink->flink = node -> flink;
    
        Node->flink->blink= node ->blink;
    
        Return0;
    
    }

     

    那么四个字节的利用我们可以做什么呢?

     

    1.内存变量:修改能影响程序执行的重要标志变量,例如更改身份验证函数的返回值。

    2.代码逻辑:修改代码段重要函数关键逻辑,如程序分支处的判断逻辑。

    3.函数返回地址:堆溢出也可以利用DWORD SHOOT更改函数返回地址。

    4.攻击异常处理:程序产生异常,Windows转入异常处理机制,包括SEH等。

    5.函数指针:如C++的虚函数调用。改写这些指针后,函数调用往往就可以劫持进程。

    6.PEB中线程同步函数入口地址:每个进程PEB存放着一对同步指针,指向RtlEnterCriticalSection()和RtlLeaveCriticalSection(),并且被ExitProcess()函数调用。

     

     

     

     

  • 相关阅读:
    VC 常见问题百问
    python windows 环境变量
    Check server headers and verify HTTP Status Codes
    Where are the AES 256bit cipher suites? Please someone help
    outlook 如何预订会议和会议室
    安装Axis2的eclipse插件后,未出现界面
    windows 环境变量
    python 时间日期处理汇集
    openldap学习笔记(使用openldap2.3.32)
    set p4 environment in windows
  • 原文地址:https://www.cnblogs.com/zibility/p/5707624.html
Copyright © 2011-2022 走看看