8.pwn入门新手学堆详细笔记

堆的概念和特性

1.堆是一种在程序运行时动态分配的内存。所谓动态时指所需内存的大小在程序设计时不能预先决定,需要在程序运行时参考用户的反馈
2.堆在使用时需要程序员用专门函数进行申请,堆内存申请有可能成功,也有可能失败
3.一般用一个堆指针使用申请得到的内存 读 写 释放 都通过这个指针来完成
4.使用完毕后需要把堆指针传给堆指针释放函数回收这片内存,否则会造成内存泄露
5.堆的生长方向是从低地址向高地址生长的

堆和栈的区别

在这里插入图片描述

堆的管理策略和数据结构

对于堆管理来说,响应程序的内存使用申请就意味着要在杂乱的堆区中辨别出哪些内存正在被使用,哪些内存时空闲的,并最终寻找到一片恰当空闲内存区域,以指针形式返回给程序
那么杂乱呢时堆区经过反复的申请 释放操作指挥,原本大片空闲内存区可能呈现出 大小不等且空闲块,占用块相间隔的凌乱状态

堆块

出于性能的考虑,堆区的内存按不同大小组织成块,以堆块为单位进行标识而不是传统的按字节标识,一个堆块包括两个部分:块首和块身
块手是一个堆块头部的几个字节,用来标识这个堆块自身的信息,块身是紧跟在块首后面的部分,也是最终分配给用户使用的数据区

注意:堆管理系统所返回的指针一般指向块首的起始位置,在程序中是感觉不到块首的存在的,然而连续的进行内存申请时,可能会发现返回的内存之间存在空隙 那就是块首

堆表

堆表一般位于堆区的起始位置,用于索引堆区中所有堆块的重要信息,包括堆块的位置、堆块的大小、空闲还是占用,堆表的数据结构决定了整个堆区的组织方式,是快速检索空闲块、保证堆分配效率的关键
在这里插入图片描述在windows中,占用态的堆块被使用它的程序索引,而堆表只索引所有空闲态的堆块,最重要的堆表有两种,空闲双向链表,和快速单项链表

空表

空闲的堆块的块首包含一对重要的指针,这对指针用于将空闲堆块组织成双向链表,按照堆块大小不同,空表总共被分为128条
堆区一开始的堆表区中有一个128项的指针数组,被称为空表索引,该数组的每一项包括两个指针,用于标识一条空表。
空闲堆块的大小=索引项*8(字节)
在这里插入图片描述

快表

块表时windows用来加速堆块分配而采用的一种堆表,之所以把它叫做快表是因为,这类单向链表从来不会发生堆块合并(其中空闲块块首被设置为占用态)用来防止堆块合并
快表也有128条,组织结构与空表类似,只是其中的堆块按照单链表组织,,快表总是被初始化为空,而且每条快表最多有4个结点,故很快被填满。
在这里插入图片描述

堆中的操作

堆中的操作可以时可以分为堆块分配、堆块释放和堆块合并三种,其中分配和释放是在程序提交申请和执行,而堆块合并则时由堆管理系统自动完成的。

1.堆块分配

快表中分配堆块比较简单包括:寻找到大小匹配的空闲堆块,将其状态修改为占用态 把它从堆表中卸下 最后返回一个指向堆块快身的指针给程序使用
普通空表分配时找最优的空闲块配,若失败则寻找次优的空闲块分配,即最小的能够满足要求的空闲块
零号空表 按照大小升序链 着大小不同的空闲块,故在分配时 先从free[0]
反向查找最后一个块(即表中最大快),看能否满足要求,如果满足要求,再正向搜索最小能够满足要求的空闲堆块进行分配

2 .堆块释放

将堆块状态改为空闲,链入相应的堆表
所有的释放块都链入堆表的末尾
分配的时候也先从堆表末尾拿
快表最多只有4项
在这里插入图片描述

3 堆块合并

经过反复的申请和释放操作 堆区会产生很多内存碎片 堆块合并主要为了合理有效的利用内存,堆管理系统进行了堆块合并,堆块合并包括 将两个块从空闲链表中 卸下、合并堆块、调整合并后大块信息、将新快重新链入空闲链表
在这里插入图片描述

当堆管理系统发现两个空闲堆块彼此相邻的时候,就会进行堆块合并
当一个堆刚被初始化时,它的堆块状况是非常简单的
只有一个空闲的大块,这个块被称为尾块
空闲态堆块和占用态堆块的块首基本一致,只是将块首后数据区的前8个字节用于存放空表指针

在这里插入图片描述

强调

快表只有再精确匹配时才会分配,不存在 搜索次优解和找零钱现象

堆分配函数之间的调用

所有的堆分配函数最终都将使用ntdll.dll 中的RtlAllocateHeap()函数进行分配
这个函数 也是再用户态能够看到的最底层的堆分配函数、
在这里插入图片描述

那么在 ctf中 我们怎样去运用堆呢
https://www.anquanke.com/post/id/163971 参考文章
CTF pwn 中最通俗易懂的堆入坑指南

发布了9 篇原创文章 · 获赞 20 · 访问量 1513

猜你喜欢

转载自blog.csdn.net/qiudalaojiao/article/details/104393608