当使用!heap -a 004e0000转储win32进程的堆(大多数进程在堆中具有较高的内存消耗,例如IE)时,我发现特定堆的多个段,例如,

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


我的问题是

问题1.为什么必须将单个堆分成多个段?

问题2。大多数时候,我发现两个细分之间有很大的差距。例如,在下面的图像中,Segment00实际上在0x005e0000处结束(其中开始未提交的字节),而Segment01的入门在0x05b60000处开始。

为什么会有这个缺口?我们不能使用相同的细分(Segment00)进行进一步分配吗?



问题3.如何从进程内存或更具体的堆偏移量中找到特定堆中存在的段数及其地址(例如,heap_handle + 0xsomeoffset?

最佳答案

我认为,作为对问题3的回答,我发现了一种“ hacky”方式从内存中获取段基地址。

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


我们采用堆0x00790000并列出其中的所有段。

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)


现在是时候从内存中手动获取相同的Segment基址了。

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
   ..
   ..


我们对SegmentListEntry感兴趣(这是@ offset 0x010)

我们从地址heap_base + 0x10转储2个DWORD

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


然后,我们采用BLINK(表示上述输出的第二个DWORD,即0x007900a8)并从此处转储2个DWROD。我们一直在做,直到从开始处到达相同的指针,即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


由于我们从开始处到达了同一点,因此我们可以在这里停止。

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


现在看一下上面得到的值。如果从所有值中减去16(0x007900a8和0x007900a8除外),您将获得段基地址。

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


哪个是

00790000
053a0000
05d40000
063e0000
09ce0000

10-04 13:16