作为问题 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
..
..
我们感兴趣的是段列表条目(这是@偏移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