堆溢出原理
堆是一种在程序运行时被动态丢弃的内存。
使用特殊功能应用程序。
通常,堆指针用于操作堆。
它需要在使用后释放。
1.堆的结构和管理(不考虑堆缓存、低碎片堆、虚拟分配)
堆的数据结构包括堆块和堆表。
堆块:堆区域中的内存根据不同的大小被组织成堆。
已占用堆块的结构包括:头和数据。
块头在堆块之前几个字节,堆块标识它自己的大小,是否空 idle和其他信息。
块体实际上是可以分配给程序的数据区。
堆块结构的管理由空表和快速表完成,它们只存储空空闲堆块
内存堆块根据大小进行分类,并可以根据大小分为小块
根据应用需求块的不同大小,它们的分配方法也会有所不同。
不同大小堆块的分配和释放方法
空 table (freelist)是由空空闲堆块组织的双向链表。根据大小分为128篇文章。
空表索引的第一项称为“零表”,它存储大于或等于1024字节(小于512kb)的堆块
剩余的空表索引存储下标*8字节大小的空空闲堆块。
空表格结构
由于需要存储双向指针,空 table中的堆块获得了用于存储双向链表指针的blink和blink结构。
空表中安装的堆块的结构
分配完成后,堆块的指针区域flink和blink将被数据覆盖。
后备是一种堆表,在窗口中用来加速堆块分配。与空表相比,不会有堆块合并和更改(因为在空表的视图中,存储在fast表中的空空闲区域被占用,块头被设置为已占用状态),fast表最多只有4项。
快速手表结构
像空表一样,由于需要存储指针,快速表中的堆块得到flink结构,当flink被分配时,它将被数据覆盖。
堆中的操作可以分为分配、释放和合并。
在快速表中,分配很简单:找到匹配的大小,分配它,从链表中移除它,并返回指向程序使用的块本身的指针。
零表中的堆块按升序排序,因此首先检查最后一比邻最新章节个堆块的大小是否满足要求,然后向前搜索可以找到满足要求的最小空空闲堆块。
在common 空表中,首先找到刚好满足大小要求的堆块,失败后,找到满足要求的最小空备用块。
在空表中,当堆块的分配不能完全满足大小要求时,会出现“变化”现象。分配次优的堆块,并在满足要求后将空的标头重新标记到空表中。
堆块的合并是针对重复分配和应用后的内存碎片。当堆管理系统发现甚至一个空空闲堆块彼此相邻时,它将合并并成为一个大堆块。
堆块的合并
2.堆溢出的原理
简而言之,堆块中数据区的存储超过了分配的大小,因此覆盖了下一个堆块的结构。
从空表格中移除桩的示例
从空表中卸载堆块
当空空闲堆块被移除时,为了保持其他空空闲堆块的信息完整,有必要改变前堆块和后堆块中的flink和blink的信息。
与快速表类似,只有前一个节点用于保存被移除节点的flink结构。
然而,如果我们在当前堆块中写入更多的数据区域来覆盖头,或者甚至闪烁下一个空空闲堆块,那么当这个空空闲堆块被使用并从空表或快速表中移除时,我们实际上控制相关节点的前向或后向指针。快速表或空表会认为假flink或blink中的地址是空空闲堆块,因此它会在分配下一个空空闲堆块时写入假地址。这种攻击实现了任意地址写入。
3.例子
环境:windows xp sp3 vc6.0调试
在这个实验环境中,str的地址被固定为0x12ff64
源代码
运行截图
堆栈字符串的值
初始化时,堆区域中只有一个尾块,堆区域的起始地址是003b0000,空表的地址是偏移量0x178。
快速表的偏移量为0x688,唯一空空闲块(尾部块)的当前偏移量为0x1e90(如果快速表未启用,尾部块将在0x688处偏移,并且尾部块将在快速表启用后开始向后移动)。
已初始化空表
在初始化期间,只有f仙王的日常生活reelist[0]有一个值并指向尾部块,其他的指向它们自己,即空
床尾
尾部块中的指针指向freelist [0],它指向尾部块,但实际上指针指向它自己
但是当尾块被占用时,指针区域将被数据覆盖
a = heapaloc(hheap,heap_zero_memory,0x 10);
这段代码通过堆溢出将aaaaaaaaaa写入字符串变量
从堆中为a分配了0x10 空并且块大小为0x8+0x10=0x18
b = heapaloc(hheap,heap_zero_memory,0x 10);
从堆中为b分配了0x10 空并且b的块大小为0x8+0x10=0x18
在空表中,空空闲堆区的起始地址变为0x003b1e90+2x(0x18)=0x003b1ec0
空表格
heapfree(hheap,0,b);
释放b,在空表中没有变化,b将被放入快速表中备用,并获得flink结构
快速表中的堆块结构
快速表中的块
快表
空表未更改
空表格
(甲& # 34;xxxxxxxxxxxxxxxxxaaabbbb \ x64 \ xff \ x12 \ x00 & # 34;,28);
此代码的执行将溢出。
溢出覆盖b的块结构,其中aaaabbbb覆盖报头,然后是x64xffx12x00(即
0x0012ff64是str) covers flink的地址
理论图
堆区域
b = heapaloc(hheap,heap_zero_memory,0x 10);
在这里,燧石覆盖的乙是从快速检索表。当快速表中的块被移除时,块中的块被写入快速表。到目前为止,快速表认为这个地址有一个与b大小相同的空备用块
c = heapaloc(hheap,heap_zero_memory,0x 10);
这里,分配了c,赋予快速表优先权,但是快速表认为正好与c的大小一致的空 free块的数据区地址是0x0012ff64
因此,将在堆叠区域中形成块结构,即c
(c ,& # 34;aaaaaaaaaaaa \ n & # 34);
在这里,写c实现了任意内存写,实际上是写字符串的位置,并通过堆溢出实现了修改字符串内容
堆栈区域字符串
部分数据和数字来自于0day security:软件漏洞分析技术(第二版)
源代码来自《加密与解密》(第四版)的源代码
文章来源:www.atolchina.com