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 中最通俗易懂的堆入坑指南

發佈了8 篇原創文章 · 獲贊 13 · 訪問量 1446
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章