您的位置:首页 > 编程语言 > C语言/C++

Windows C++代码heap分析详解

2012-09-21 14:28 543 查看
上次写了一篇文章,Windows代码heap内存分析实战

由于时间的关系,写的不是很详细,于是有朋友建议写的详细些,于是有了本文。

Windows C++代码heap分析详解

Windows代码占用的内存主要是堆和栈,其中栈内存又被称为自动内存,一般为系统自动管理,所以常见的问题主要发生在堆内存上。系统中如果分配了堆内存而不释放,或者错误释放,都会产生问题。

首先来分析一下堆内存的主要结构:

对于普通的堆:

1. CreateHeap -> creates a _HEAP

2. AllocHeap -> creates a _HEAP_ENTRY

对于页堆 (gflags.exe /i +hpa):

1. CreateHeap -> creates a _DPH_HEAP_ROOT (+ _HEAP + 2x _HEAP_ENTRY)

2. AllocHeap -> creates a _DPH_HEAP_BLOCK

也就是说对于页堆,有额外的数据表征其内容,当让,对于同样堆分析命令,对于两种堆也会输出不同的内容。

对于普通的堆,分别执行的分析命令和结果如下:

0:001> !heap -s

NtGlobalFlag enables following debugging aids for new heaps:

validate parameters

stack back traces

Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast

(k) (k) (k) (k) length blocks cont. heap

-----------------------------------------------------------------------------

00170000 58000062 1024 64 64 12 3 1 0 0 L

00270000 58001062 64 24 24 11 1 1 0 0 L

00280000 58008060 64 12 12 10 1 1 0 0

00370000 58001062 64 28 28 9 1 1 0 0 L

00390000 58001062 64 56 56 5 2 1 0 0

003a0000 58001062 1088 72 72 16 3 2 0 0 L

003f0000 58001062 64 20 20 5 2 1 0 0 L

01a20000 58001062 64 20 20 1 1 1 0 0 L

02090000 58001062 64 12 12 4 1 1 0 0 L

-----------------------------------------------------------------------------

0:001> !heap -p

Active GlobalFlag bits:

hpc - Enable heap parameter checking

ust - Create user mode stack trace database

StackTraceDataBase @ 00430000 of size 01000000 with 0000037f traces

active heaps:

- 170000

HEAP_GROWABLE HEAP_TAIL_CHECKING_ENABLED HEAP_FREE_CHECKING_ENABLED

- 270000

HEAP_GROWABLE HEAP_TAIL_CHECKING_ENABLED HEAP_FREE_CHECKING_ENABLED HEAP_CLASS_1

- 280000

HEAP_TAIL_CHECKING_ENABLED HEAP_FREE_CHECKING_ENABLED HEAP_CLASS_8

- 370000

HEAP_GROWABLE HEAP_TAIL_CHECKING_ENABLED HEAP_FREE_CHECKING_ENABLED HEAP_CLASS_1

- 390000

HEAP_GROWABLE HEAP_TAIL_CHECKING_ENABLED HEAP_FREE_CHECKING_ENABLED HEAP_CLASS_1

- 3a0000

HEAP_GROWABLE HEAP_TAIL_CHECKING_ENABLED HEAP_FREE_CHECKING_ENABLED HEAP_CLASS_1

- 3f0000

HEAP_GROWABLE HEAP_TAIL_CHECKING_ENABLED HEAP_FREE_CHECKING_ENABLED HEAP_CLASS_1

- 1a20000

HEAP_GROWABLE HEAP_TAIL_CHECKING_ENABLED HEAP_FREE_CHECKING_ENABLED HEAP_CLASS_1

- 2090000

HEAP_GROWABLE HEAP_TAIL_CHECKING_ENABLED HEAP_FREE_CHECKING_ENABLED HEAP_CLASS_1

0:001> !heap -stat

_HEAP 003a0000

Segments 00000002

Reserved bytes 00110000

Committed bytes 00012000

VirtAllocBlocks 00000000

VirtAlloc bytes 00000000

_HEAP 00170000

Segments 00000001

Reserved bytes 00100000

Committed bytes 00010000

VirtAllocBlocks 00000000

VirtAlloc bytes 00000000

_HEAP 00390000

Segments 00000001

Reserved bytes 00010000

Committed bytes 0000e000

VirtAllocBlocks 00000000

VirtAlloc bytes 00000000

_HEAP 00370000

Segments 00000001

Reserved bytes 00010000

Committed bytes 00007000

VirtAllocBlocks 00000000

VirtAlloc bytes 00000000

_HEAP 00270000

Segments 00000001

Reserved bytes 00010000

Committed bytes 00006000

VirtAllocBlocks 00000000

VirtAlloc bytes 00000000

_HEAP 01a20000

Segments 00000001

Reserved bytes 00010000

Committed bytes 00005000

VirtAllocBlocks 00000000

VirtAlloc bytes 00000000

_HEAP 003f0000

Segments 00000001

Reserved bytes 00010000

Committed bytes 00005000

VirtAllocBlocks 00000000

VirtAlloc bytes 00000000

_HEAP 02090000

Segments 00000001

Reserved bytes 00010000

Committed bytes 00003000

VirtAllocBlocks 00000000

VirtAlloc bytes 00000000

_HEAP 00280000

Segments 00000001

Reserved bytes 00010000

Committed bytes 00003000

VirtAllocBlocks 00000000

VirtAlloc bytes 00000000

对于页堆堆,分别执行的分析命令和结果如下:

0:001> !heap -s

Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast

(k) (k) (k) (k) length blocks cont. heap

-----------------------------------------------------------------------------

00270000 00000002 1024 12 12 4 1 1 0 0 L

00380000 00001002 64 24 24 16 1 1 0 0 L

00390000 00008000 64 12 12 10 1 1 0 0

003e0000 00001002 64 12 12 4 1 1 0 0 L

018e0000 00001002 64 12 12 4 1 1 0 0 L

01ad0000 00001002 64 32 32 24 1 1 0 0 L

02020000 00001002 64 12 12 4 1 1 0 0 L

02130000 00001002 64 12 12 4 1 1 0 0 L

02bd0000 00001002 64 12 12 4 1 1 0 0 L

02ce0000 00001002 64 12 12 4 1 1 0 0 L

-----------------------------------------------------------------------------

0:001> !heap -p

Active GlobalFlag bits:

hpa - Place heap allocations at ends of pages

StackTraceDataBase @ 00430000 of size 01000000 with 00000376 traces

PageHeap enabled with options:

ENABLE_PAGE_HEAP

COLLECT_STACK_TRACES

active heaps:

+ 170000

ENABLE_PAGE_HEAP COLLECT_STACK_TRACES

NormalHeap - 270000

HEAP_GROWABLE

ReadMemory error for address eeddccee

Use `!address eeddccee' to check validity of the address.

0:001> !heap -stat

ReadMemory error for address eeddccee

Use `!address eeddccee' to check validity of the address.

_HEAP 00170000

Segments 00000001

Reserved bytes 00100000

Committed bytes 00003000

VirtAllocBlocks 00000000

VirtAlloc bytes 00000000

从分析结果我们可以看出!heap -p 命令对于不同的堆输出的内容是不同的,对于普通的堆,!heap –s 和!heap –p 产生相同的地址,而对于页堆,他们的输出就有了显著的不同 。另外对于普通的堆,heap handle和heap address 一样,而对于页堆,其也有很大的区别。

另外值得一提的是!heap –p –a 这条神奇命令,别看这条命令带-p 其实这条命令根本不需要开启页堆选项,只要有 +ust就行了

!heap -p -a [UserAddr....UserAddr+AlloSize]

正常情况下这条命令可以打相应的callstack.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: