debugging - 进程堆段及其必要性

标签 debugging heap-memory reverse-engineering windbg

使用 !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)来进一步分配吗?

enter image description here

问题 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)

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

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

关于debugging - 进程堆段及其必要性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28524619/

相关文章:

algorithm - 使用程序计数器(指令指针)值中的模式检测循环

c - 从 GDB 解码 ARM 指令

debugging - netlogo 中的 while 循环调试

node.js - 如何通过 Google Cloud 调试在 Docker 容器中运行的 Nodejs 应用程序

java - 在 Tomcat 中设置堆大小

android - .apk 没有正式的格式规范吗?

c++ - 已加载本地生成的小型转储,但远程生成的小型转储无法加载调用堆栈和符号

powershell - Redis 服务器不能运行超过 1024M 的 maxheap

python - 总分配超过堆内存的 95.00%(960,285,889 字节)- pyspark 错误

debugging - salt 栈 : Reverse engineering where a file comes from