WinDBG提供了!heap指令幫助我們查找heap,同時我們也可以通過dt和MS SYMBOL來了解memory layout。
假設我們有下面一個小程式。
複制代碼
int _tmain(int argc, _TCHAR* argv[])
{
char * pChar = new char[2];
pChar[0] = 'a';
delete [] pChar;
return 0;
}
在WinDbg裡面啟動這個程式,運作到new操作結束。這時候我們可以得到pChar指針。
我們可以通過!heap -x 來查找對應的Heap Block
!heap -x 00343818
00343810 00343818 00340000 00340640 20 38 1e busy extra fill
從上面我們知道,這個heap block位址是00343810,使用者記憶體位址是00343818,整個heap block大小是0x20。Heap Block Meta Data占據了前面8個位元組 (這也解釋了為什麼使用者記憶體位址的起始位址)。未使用的空間有1e(因為我們申請了2個byte) Flags是busy。
有了Heap Block位址,我們就可以運作下面指令
0:000> dt _HEAP_ENTRY 0X00343810
ntdll!_HEAP_ENTRY
+0x000 Size : 4
+0x002 PreviousSize : 7
+0x000 SubSegmentCode : 0x00070004
+0x004 SmallTagIndex : 0x49 'I'
+0x005 Flags : 0x7 ''
+0x006 UnusedBytes : 0x1e ''
+0x007 SegmentIndex : 0 ''
我們可以看到Size 是4.為什麼是4了?因為這兒的機關不是byte,而是heap granularity。通常是8.是以我們可以計算:4*8=32=0x20。
我們再看一下記憶體布局。
0:000> dd 00343810
00343810 00070004 001e0749 abab0198 abababab
00343820 feeeabab feeefeee 00000000 00000000
上圖是每個Heap Block的說明。對比我們的memory layout,我們就可以得到類似的資訊。
我們也可以下面的指令來得到更詳細的資訊。
0:000> !heap -i 00343810
Detailed information for block entry 00343810
Assumed heap : 0x00340000 (Use !heap -i NewHeapHandle to change)
Owning segment : 0x00340000 (offset 0)
Block flags : 0x7 (busy extra fill )
Total block size : 0x4 units (0x20 bytes)
Requested size : 0x2 bytes (unused 0x1e bytes)
Previous block size: 0x7 units (0x38 bytes)
Previous block : 0x003437d8
Next block : 0x00343830
運作完pChar[0] = 'a';這條指令,我們再看看記憶體。
0:000> dc 00343818
00343818 abab0161 abababab feeeabab feeefeee a...............
我們可以看到'a'寫進去了。