最近看的一本不错的书《0day安全》,里面关于堆的内容win2000版本的,内核比较老了,新版的win内核堆结构和书中的内容有出入,正好考虑到好久没写文章了,就写下一篇水文,以下内容均为个人对内存堆结构的一些猜测,通过windbg做了一些验证,官方对于堆的管理没有明确说法,如有错误,望指正。
禁止留联系方式
调试工具:windbg
系统版本:win11
一下内容只在32位的基础上讨论,并且只讨论空表,不对堆表其他内容做判断
首先win2000的内核关于堆的结构中,空表位置是在0x178,较新一点的系统实在0xc0,使用windbg可以查看
然后再就是通过空表查看表头的时候数据不匹配的问题,是因为新版的加入了编码验证,也是为了防止堆攻击,是需要堆表(结构体为_HEAP,喜欢的师傅可以windbg自己看下)中的Encoding项
通过堆表数据结构在内存中查到encoding的项,然后通过encoding中的内容与空表中的内容做异或操作就可以了
还有个问题就是ntdll中堆表数据结构使用的是heap_entry描述空表双链表结构,没有使用空表头结构,空表堆块头结构是ntdll!_HEAP_FREE_ENTRY,已经使用的堆块头结构是ntdll!_HEAP_ENTRY
下面是关于堆释放后在空表的讨论:
书中的内容和较新一点的win系统中的实际内容有所出入,查的各种资料也全是这本书的那一套,索性就直接调试看下,调试了半天才最后确定下整个堆的结构。
首先空表结构改版最大的就是在整个堆开始字节中的_HEAP结构中的空表,下面图是win2000版本(此版本代表比较老一些的win版本)空表是在偏移0x178,然后下面的内容不难看出这是一个地址数组结构,后面还有很多就不放了
下面的图是win11(此版本代表比较新一些的win版本)
这里从0xc0这个地址看到空表只有八个字节(这八个字节的数据结构是一个双向链表的指针数据,FLINK是指向后面,BLINK指向前面)这个结构也直接记录了空表内块头的分布,为什么使用LIST_ENTRY这个只有两个指针的结构体,而从微软官方的符号服务器上收到的数据是这个空表与后面堆块头结构使用相同的结构体,即LIST_ENTRY。
这里也是困扰我比较长时间的点,我用一个图来表示新的堆结构
也就是块头由dll函数去用内存地址-8来操作,使堆表中_HEAP的结构与块头的数据结构匹配,用这样的方式来保证这个双向链表的作用只有闭环查找。
下图是传统的堆结构可以做下对比
新版堆结构采用回环链表,使整个表循环起来,并按照从小到大顺序,采用最优次优匹配原则
|