堆的初步认知

堆的分配是在程序运行时完成的,分配速度较为缓慢,但是堆的可用空间非常的大。常见的堆空间操作有如:new,malloc(申请);free,delete(释放),底层函数RtlAllocateHeap(ntdll.dll中),更详细的函数信息查看MSDN。堆分配的空间较为碎片化,需要对堆块的管理:按照堆块的大小分类组织在一起,在堆区的起始位置建立堆表用于索引堆块;而每一个堆块头部也记录着本块大小、空闲与否等(8字节),空闲块区还有前向指针(flink),后向指针(binlk),一共16字节。


堆的初步认知_第1张图片

每一次堆分配或者堆释放时,都将从空堆表末尾进行操作。堆的操作存在修改链表链接和块首信息,构造伪造的节点就可以实现一次内存读写的操作。


堆的初步认知_第2张图片

堆溢出的时候,就是溢出修改堆的首部指针,当块卸下的时候,将实现向我们在blink处写的地址target写入原flink处的修改值payload(与此同时在blink处写的数据也将写到flink偏移4字节的位置去)。一般target选取为函数返回,异常发生或函数调用等。也可以用于目标地址变量值的修改,或填入nop之类修改函数流程。特别的使用方法就是修改PEB中线程同步的函数入口地址,进程退出时,exitprocess调用线程中的rtlentercriticalsection等函数来处理线程间实现临界段锁的数据清理。

调试堆与常态管理有不同:调试堆不使用块表只用空表分配;所有堆块添加16字节尾部用于防止程序溢出(不是堆溢出);块首标志位不同。如果堆初始化结束后再attach程序可以看见真实状态的堆。

在多线程的程序里,每个线程都有其自己独立的栈,它们都共享一个堆。栈是面向线程的而堆是面向进程的。

linux下的堆与windows平台下差别不大:

堆的初步认知_第3张图片

你可能感兴趣的:(堆的初步认知)