Process Heap Segments And Their Necessity
Asked Answered
L

1

3

While dumping heap of a win32 processes (Mostly in process which has high heap memory consumption like IE ) using !heap -a 004e0000 I find multiple segments of a particular heap like ,

Heap entries for Segment00 in Heap 004e0000
Heap entries for Segment01 in Heap 004e0000
Heap entries for Segment02 in Heap 004e0000

My questions are

Question 1. Why its necessory to divide single heap into multiple segments ?

Question 2. Most of the times I find a large gap between two segments. For example in below image Segment00 actually ends @ 0x005e0000 (Where un-commited bytes started) and Segment01 getting started @ 0x05b60000.

Why this gap ?? Couldn't we use the same segment (Segment00)for further allocation ??

enter image description here

Question 3. How can I find the number of segments present in particular heap and their addresses from process memory memory or more specifically heap offset (example heap_handle+0xsomeoffset ?

Leahy answered 15/2, 2015 at 9:13 Comment(3)
Probably it's not necessary and segments only exist to save some bytes of memory. You can cast _HEAP to _HEAP_SEGMENT. Look at dt _HEAP and dt _HEAP_SEGMENT. It should be possible to get the number of segments from the SegmentList property of _HEAP.Lorelle
One reason why it is necessary for the the heap manager to support multiple segments is that it isn't necessarily the only thing allocating address space. If the heap manager runs out of room in a heap's initial address space allocation the only option is a new allocation, which will not necessarily be contiguous with the previous one. (Having multiple segments might also be useful in a multi-threaded program, as each segment could be locked separately - though as far as I know Windows does not in fact do this.)Justinjustina
@ThomasW. I tried it with a heap which has 4 segments, If you take a look @ pastebin.com/RkC11JLn I'm able to find base address of first two heap segments manually from memory, but not sure how can i get next two segment base addresses. And also to continue that I need to know maximum # of segs in any heap.Leahy
L
2

As an answer to Question 3, I think, I've found a "hacky" way to get the segment base address from memory.

0:027> !heap
Index   Address  Name      Debugging options enabled
  1:   00790000                
  2:   004d0000                
  3:   028b0000                
  4:   02a40000                
  5:   02fa0000                
  6:   03b00000                
  7:   02ca0000                
  8:   03ac0000                
  9:   04d80000                
 10:   0a850000                

We take heap 0x00790000 and list all Segments in it.

0:027> !heap 00790000
Index   Address  Name      Debugging options enabled
  1:   00790000 
    Segment at 00790000 to 00890000 (00100000 bytes committed)
    Segment at 053a0000 to 054a0000 (00100000 bytes committed)
    Segment at 05d40000 to 05f40000 (00200000 bytes committed)
    Segment at 063e0000 to 067e0000 (00400000 bytes committed)
    Segment at 09ce0000 to 0a4e0000 (007fa000 bytes committed)

Now its time to get the same Segment base addresses manually from memory.

0:027> dt _HEAP 00790000 
ntdll!_HEAP
   +0x000 Entry            : _HEAP_ENTRY
   +0x008 SegmentSignature : 0xffeeffee
   +0x00c SegmentFlags     : 0
   +0x010 SegmentListEntry : _LIST_ENTRY [ 0x53a0010 - 0x7900a8 ]
   +0x018 Heap             : 0x00790000 _HEAP
   +0x01c BaseAddress      : 0x00790000 Void
   ..
   ..

We are interested in SegmentListEntry (Which is @ offset 0x010)

We dump 2 DWORD from address heap_base + 0x10

0:027> dd 00790000 + 0x10 L2
00790010  053a0010 007900a8

Then we take the BLINK (which means the 2nd DWORD of above output, which is 0x007900a8) and dump 2 DWROD from there. And we keep doing it until we reach the same pointer from where we started, which is 0x007900a8

0:027> dd 007900a8 L2
007900a8  00790010 09ce0010
0:027> dd 09ce0010 L2
09ce0010  007900a8 063e0010
0:027> dd 063e0010 L2
063e0010  09ce0010 05d40010
0:027> dd 05d40010 L2
05d40010  063e0010 053a0010
0:027> dd 053a0010 L2
053a0010  05d40010 00790010
0:027> dd 00790010 L2
00790010  053a0010 007900a8

Since we reached the same point from where we started, we can stop here.

0:027> dd 007900a8 L2
007900a8  00790010 09ce0010

Now take a look at the values we got above. If you subtract 16 from all (except 0x007900a8 and 0x007900a8)them you will get Segment Base addresses.

0:027> ? 09ce0000 + 16
Evaluate expression: 164495382 = 09ce0016

Which are

00790000
053a0000
05d40000
063e0000
09ce0000
Leahy answered 16/2, 2015 at 20:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.