Heap, Heap Segment, Heap Entry

在我们的每一个进程中都有很多HEAP,一些是系统默认的heap,一些是我们创建的Heap,比如说C Runtime Heap。

每一个Heap包括若干个Heap Segment。每一个Heap Segment又包括若干个Heap Block。我们每一次调用new操作,系统就会返回一个Heap Block。

我们可以通过WinDBG来看看这里面的关系。

0:000> dt _PEB @$peb
HeapAllocation!_PEB
   +0x000 InheritedAddressSpace : 0 ''
   +0x001 ReadImageFileExecOptions : 0 ''
   +0x002 BeingDebugged    : 0x1 ''
   +0x003 SpareBool        : 0 ''
   +0x004 Mutant           : 0xffffffff
   +0x008 ImageBaseAddress : 0x00400000
   +0x00c Ldr              : 0x00251ea0 _PEB_LDR_DATA
   +0x010 ProcessParameters : 0x00020000 _RTL_USER_PROCESS_PARAMETERS
   +0x014 SubSystemData    : (null)
   +0x018 ProcessHeap      : 0x00150000
   +0x01c FastPebLock      : 0x7c980600 _RTL_CRITICAL_SECTION
   +0x020 SparePtr1        : 0x7c901000
   +0x024 SparePtr2        : 0x7c9010e0
   +0x028 EnvironmentUpdateCount : 1
   +0x02c KernelCallbackTable : (null)
   +0x030 SystemReserved   : [1] 0
   +0x034 ExecuteOptions   : 0y00
   +0x034 SpareBits        : 0y000000000000000000000000000000 (0)
   +0x038 FreeList         : (null)
   +0x03c TlsExpansionCounter : 0
   +0x040 TlsBitmap        : 0x7c9805c0
   +0x044 TlsBitmapBits    : [2] 1
   +0x04c ReadOnlySharedMemoryBase : 0x7f6f0000
   +0x050 ReadOnlySharedMemoryHeap : 0x7f6f0000
   +0x054 ReadOnlyStaticServerData : 0x7f6f0688  -> (null)
   +0x058 AnsiCodePageData : 0x7ffb0000
   +0x05c OemCodePageData  : 0x7ffc1000
   +0x060 UnicodeCaseTableData : 0x7ffd2000
   +0x064 NumberOfProcessors : 2
   +0x068 NtGlobalFlag     : 0x70
   +0x070 CriticalSectionTimeout : _LARGE_INTEGER 0xffffe86d`079b8000
   +0x078 HeapSegmentReserve : 0x100000
   +0x07c HeapSegmentCommit : 0x2000
   +0x080 HeapDeCommitTotalFreeThreshold : 0x10000
   +0x084 HeapDeCommitFreeBlockThreshold : 0x1000
   +0x088 NumberOfHeaps    : 3
   +0x08c MaximumNumberOfHeaps : 0x10
   +0x090 ProcessHeaps     : 0x7c97ffc0  -> 0x00150000
   +0x094 GdiSharedHandleTable : (null)
   +0x098 ProcessStarterHelper : (null)
   +0x09c GdiDCAttributeList : 0
   +0x0a0 LoaderLock       : 0x7c97e178 _RTL_CRITICAL_SECTION
   +0x0a4 OSMajorVersion   : 5
   +0x0a8 OSMinorVersion   : 1
   +0x0ac OSBuildNumber    : 0xa28
   +0x0ae OSCSDVersion     : 0x300
   +0x0b0 OSPlatformId     : 2
   +0x0b4 ImageSubsystem   : 3
   +0x0b8 ImageSubsystemMajorVersion : 5
   +0x0bc ImageSubsystemMinorVersion : 0
   +0x0c0 ImageProcessAffinityMask : 0
   +0x0c4 GdiHandleBuffer  : [34] 0
   +0x14c PostProcessInitRoutine : (null)
   +0x150 TlsExpansionBitmap : 0x7c9805b8
   +0x154 TlsExpansionBitmapBits : [32] 0
   +0x1d4 SessionId        : 0
   +0x1d8 AppCompatFlags   : _ULARGE_INTEGER 0x0
   +0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER 0x0
   +0x1e8 pShimData        : (null)
   +0x1ec AppCompatInfo    : (null)
   +0x1f0 CSDVersion       : _UNICODE_STRING "Service Pack 3"
   +0x1f8 ActivationContextData : 0x00140000 _ACTIVATION_CONTEXT_DATA
   +0x1fc ProcessAssemblyStorageMap : 0x001529e0 _ASSEMBLY_STORAGE_MAP
   +0x200 SystemDefaultActivationContextData : 0x00130000 _ACTIVATION_CONTEXT_DATA
   +0x204 SystemAssemblyStorageMap : (null)
   +0x208 MinimumStackCommit : 0
   +0x20c FlsCallback      : (null)
   +0x210 FlsListHead      : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x218 FlsBitmap        : (null)
   +0x21c FlsBitmapBits    : [4] 0
   +0x22c FlsHighIndex     : 0

我们所感兴趣的是offset在0x90处的变量。它存储了我们Heap的地址。

0:000> dd 0x7c97ffc0 
7c97ffc0  00150000 00250000 00260000 00000000
7c97ffd0  00000000 00000000 00000000 00000000
7c97ffe0  00000000 00000000 00000000 00000000
7c97fff0  00000000 00000000 00000000 00000000

从上面我们可以看出现在我们有3个Heap。第一个是系统默认的Heap。

0:000> dt _HEAP 00150000
ntdll!_HEAP
   +0x000 Entry            : _HEAP_ENTRY
   +0x008 Signature        : 0xeeffeeff
   +0x00c Flags            : 0x50000062
   +0x010 ForceFlags       : 0x40000060
   +0x014 VirtualMemoryThreshold : 0xfe00
   +0x018 SegmentReserve   : 0x100000
   +0x01c SegmentCommit    : 0x2000
   +0x020 DeCommitFreeBlockThreshold : 0x200
   +0x024 DeCommitTotalFreeThreshold : 0x2000
   +0x028 TotalFreeSize    : 0xa3
   +0x02c MaximumAllocationSize : 0x7ffdefff
   +0x030 ProcessHeapsListIndex : 1
   +0x032 HeaderValidateLength : 0x608
   +0x034 HeaderValidateCopy : (null)
   +0x038 NextAvailableTagIndex : 0
   +0x03a MaximumTagIndex  : 0
   +0x03c TagEntries       : (null)
   +0x040 UCRSegments      : (null)
   +0x044 UnusedUnCommittedRanges : 0x00150598 _HEAP_UNCOMMMTTED_RANGE
   +0x048 AlignRound       : 0x17
   +0x04c AlignMask        : 0xfffffff8
   +0x050 VirtualAllocdBlocks : _LIST_ENTRY [ 0x150050 - 0x150050 ]
   +0x058 Segments         : [64] 0x00150640 _HEAP_SEGMENT
   +0x158 u                : __unnamed
   +0x168 u2               : __unnamed
   +0x16a AllocatorBackTraceIndex : 0
   +0x16c NonDedicatedListLength : 1
   +0x170 LargeBlocksIndex : (null)
   +0x174 PseudoTagEntries : (null)
   +0x178 FreeLists        : [128] _LIST_ENTRY [ 0x152af0 - 0x152af0 ]
   +0x578 LockVariable     : 0x00150608 _HEAP_LOCK
   +0x57c CommitRoutine    : (null)
   +0x580 FrontEndHeap     : 0x00150688
   +0x584 FrontHeapLockCount : 0
   +0x586 FrontEndHeapType : 0x1 ''
   +0x587 LastSegmentIndex : 0 ''

Offset在0x58处的变量, Segments存储了该Heap里面包括的Heap Segments。 0x178处的Free List则包括了所有空闲的Heap Block.

0:000> dt _LIST_ENTRY 0x00150000+0x178
HeapAllocation!_LIST_ENTRY
 [ 0x152af0 - 0x152af0 ]
   +0x000 Flink            : 0x00152af0 _LIST_ENTRY [ 0x150178 - 0x150178 ]
   +0x004 Blink            : 0x00152af0 _LIST_ENTRY [ 0x150178 - 0x150178 ]
0:000> dt _HEAP_ENTRY 0x00152af0-0x8
ntdll!_HEAP_ENTRY
   +0x000 Size             : 0xa3
   +0x002 PreviousSize     : 0x1c
   +0x000 SubSegmentCode   : 0x001c00a3
   +0x004 SmallTagIndex    : 0xaa ''
   +0x005 Flags            : 0x14 ''
   +0x006 UnusedBytes      : 0x1e ''
   +0x007 SegmentIndex     : 0 ''
因为每一个Heap Block前面都会有8个字节的meta data,所以我们需要减去8来得到地址。

我们也可以loop所有的Segment.

0:000> dd 00150000+0x58
00150058  00150640 00000000 00000000 00000000
00150068  00000000 00000000 00000000 00000000
00150078  00000000 00000000 00000000 00000000
00150088  00000000 00000000 00000000 00000000
00150098  00000000 00000000 00000000 00000000
001500a8  00000000 00000000 00000000 00000000
001500b8  00000000 00000000 00000000 00000000
001500c8  00000000 00000000 00000000 00000000
0:000> dt _HEAP_SEGMENT 00150640
ntdll!_HEAP_SEGMENT
   +0x000 Entry            : _HEAP_ENTRY
   +0x008 Signature        : 0xffeeffee
   +0x00c Flags            : 0
   +0x010 Heap             : 0x00150000 _HEAP
   +0x014 LargestUnCommittedRange : 0xfd000
   +0x018 BaseAddress      : 0x00150000
   +0x01c NumberOfPages    : 0x100
   +0x020 FirstEntry       : 0x00150680 _HEAP_ENTRY
   +0x024 LastValidEntry   : 0x00250000 _HEAP_ENTRY
   +0x028 NumberOfUnCommittedPages : 0xfd
   +0x02c NumberOfUnCommittedRanges : 1
   +0x030 UnCommittedRanges : 0x00150588 _HEAP_UNCOMMMTTED_RANGE
   +0x034 AllocatorBackTraceIndex : 0
   +0x036 Reserved         : 0
   +0x038 LastEntryInSegment : 0x00152ae8 _HEAP_ENTRY
0:000> dt _HEAP_ENTRY 0x00150680
ntdll!_HEAP_ENTRY
   +0x000 Size             : 0x303
   +0x002 PreviousSize     : 8
   +0x000 SubSegmentCode   : 0x00080303
   +0x004 SmallTagIndex    : 0x27 '''
   +0x005 Flags            : 0x7 ''
   +0x006 UnusedBytes      : 0x18 ''
   +0x007 SegmentIndex     : 0 ''

原文地址:https://www.cnblogs.com/xiaxi/p/1946828.html