【问题标题】:Process Heap Segments And Their Necessity进程堆段及其必要性
【发布时间】:2015-04-15 23:19:25
【问题描述】:

在使用 !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 ?

【问题讨论】:

  • 可能没有必要,段的存在只是为了节省一些字节的内存。您可以将_HEAP 转换为_HEAP_SEGMENT。查看dt _HEAPdt _HEAP_SEGMENT。应该可以从_HEAPSegmentList属性中获取段数。
  • 堆管理器必须支持多个段的一个原因是它不一定是唯一分配地址空间的东西。如果堆管理器在堆的初始地址空间分配中空间不足,则唯一的选择是新的分配,它不一定与前一个连续。 (拥有多个段在多线程程序中也可能很有用,因为每个段都可以单独锁定 - 尽管据我所知 Windows 实际上并没有这样做。)
  • @ThomasW。我用一个有 4 个段的堆进行了尝试,如果你看一下 @pastebin.com/RkC11JLn 我可以手动从内存中找到前两个堆段的基地址,但不确定如何获得下两个段的基地址。并且还要继续,我需要知道任何堆中的最大段数。
  • 谢谢@HarryJohnston

标签: debugging heap-memory reverse-engineering windbg


【解决方案1】:

作为对问题 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 并列出其中的所有 Segment。

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)

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

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

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

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

哪些是

00790000
053a0000
05d40000
063e0000
09ce0000

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    • 2011-10-03
    • 2014-07-28
    • 2020-07-17
    • 2015-01-03
    • 1970-01-01
    相关资源
    最近更新 更多