代碼
#include <windows.h>
int main()
{
HLOCAL h1,h2,h3,h4,h5,h6;
HANDLE hp;
hp = HeapCreate(0,0x1000,0x10000);//創建一個新的堆
_asm int 3//中斷,進入OD除錯
h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,3);
h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,5);
h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,6);
h4 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
h5 = HeapAlloc(hp,HEAP_ZERO_MEMORY,19);
h6 = HeapAlloc(hp,HEAP_ZERO_MEMORY,24);
_asm int 3
HeapFree(hp,0,h1);
HeapFree(hp,0,h3);
HeapFree(hp,0,h5);
_asm int 3
HeapFree(hp,0,h4);
_asm int 3
return 0;
}
實驗目的
簡單理解空表
實驗準備
環境:windows xp
編譯器:vc++
除錯器:OD
實驗程序
1.把OD設成默認除錯器,打開這段程式觸發例外正好卡在HeapCreate后面,這時候的正好把新建好的堆的地址傳入eax,

試了下Heap_Vis這個插件,好像不是那么好用,我用了下,直接給我卡死了,最后還是靠Ctrl+Alt+Del才救回來的(有可能是插件沖突了?懶得去搞了

2.找到堆的地址發現堆的結構前面先是一段段表,中間是虛分配表,因為堆才初始化,沒有虛分配記錄所以全都為NULL,然后就是32位的bitmap應該是來統計堆表的分配,如果表被占用則,該對應的bit位上為1.
然后接下來就是空表索引區,但是由于都沒有被占用,所有的空表都指向自己的位置,
其中零號空表(0x003a0178)指向的是尾塊,

PS:堆表表頭的結構為
| Byte | Name |
|---|---|
| 1~2 | Self Size 自身的長度 |
| 3~4 | Previous chunk size 上一節的長度 |
| 5 | Segment Index 段索引 |
| 6 | Flags 該位為1的時候,表示該表被占用了 |
| 7 | Unused bytes |
| 8 | Tag index |
| 9~b | Flink in freelist (占用態) |
| c~f | Blink in freelist (占用態) |
3.觀察到零號空表指向的尾塊表頭,表頭下面的就是指向零號空表的雙向鏈表,實際上這個堆塊開始于 0x0030680,一般參考堆塊的指標都會躍過 8 位元組的塊首,直接指向資料區,Self Size為0x130,因為堆中一個單位對應的都是八個位元組,所以總空間為 0x130 * 8,
(1)堆塊的大小包括了塊首在內,即如果請求 32 位元組,實際會分配的堆塊為 40 位元組:8位元組塊首+32 位元組塊身,
(2)堆塊的單位是 8 位元組,不足 8 位元組的部分按 8 位元組分配,
(3)初始狀態下,快表和空表都為空,不存在精確分配,請求將使用“次優塊”進行分配,這個“次優塊”就是位于偏移 0x0680 處的尾塊,
(4)由于次優分配的發生,分配函式會陸續從尾塊中切走一些小塊,并修改尾塊塊首中的size 資訊,最后把 freelist[0]指向新的尾塊位置,

3.把斷點的位置移到HeapAlloc的后面觀察每個空間的申請,
0x003a0680到0x003a06e0就是1到6號申請的空間,
開頭是02,則代表分配了2 * 8個位元組的空間,
開頭是04,則代表分配了4 * 8個位元組的空間,
然后這個時候再看尾塊的表頭的Self Size為0x120,因為前面分配了0x10的空間(2 * 4 + 4 * 2 = 0x10)
這時零表中指向尾塊的指標也變成了0x003a0700

4.把斷點的位置移到HeapFree h5的后面,觀察h1和h3鏈入了Freelist[2],h5鏈入了Freelist[4],同時觀察Flag位都變為了0,意味著恢復成了空閑態,

5.又把斷點的位置移到HeapFree之后觀察堆表h1鏈入了Freelist[2],h3脫離了Freelist[2]與h1組成的鏈表鏈入了Freelist[8],同時觀察h3開頭的02已經變成了08,此時已經完成了h3,h4,h5的合并,h5也從Freelist[4]中取下了,
堆塊合并的程序,堆塊合并可以更加有效地利用記憶體,但往往需要修改多處指標,因此,堆塊合并只發生在空表中,在強調分配效率的快表中,堆塊合并一般會被禁止(通過設定堆塊為占用態),另外,空表中的第一個塊不會向前合并,最后一個塊不會向后合并,
Freelist中指向的地址都自動跳過了堆塊頭的,也就是跳過了那8個位元組,

觀察此時Freelist[4]已經變為指向自身,Freelist[2]也只鏈入了一個h1

PS:除錯堆好像不能用OD直接載入,必須的在行程中除錯,不然堆的位置就會出現亂碼,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/87589.html
標籤:其他
上一篇:區塊鏈、位元幣、山寨幣、國家貨幣!對個人的影響 個人理解!
下一篇:區塊鏈的基礎問題(二)
