文章目录
1、搭建环境
1.1 测试程序
这里的测试程序是很简单的那种,凑合着用吧
#include "stdafx.h"
void LeakMem()
{
while (true)
{
char *pTest = new char[512];
}
}
int _tmain(int argc, _TCHAR* argv[])
{
LeakMem();
system("pause");
return 0;
}
编译好了之后,使用WinDbg打开这个exe文件,如下:
1.2 设置pdb路径和源码路径
如何设置参考其他文章,这里不再说明
2、定位
2.1 运行程序
执行g命令:
发现程序很快就退出了,这时候运行分析命令,如下:
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
FAULTING_IP:
ntdll_77a90000!LdrpDoDebuggerBreak+2b
77b3ed22 cc int 3
EXCEPTION_RECORD: ffffffffffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 0000000077b3ed22 (ntdll_77a90000!LdrpDoDebuggerBreak+0x000000000000002b)
ExceptionCode: 4000001f (WOW64 breakpoint)
ExceptionFlags: 00000000
NumberParameters: 1
Parameter[0]: 0000000000000000
CONTEXT: 0000000000000000 -- (.cxr 0x0;r)
eax=00000000 ebx=00b69000 ecx=77ae0000 edx=00000000 esi=00f51b70 edi=77a9687c
eip=77b3ed22 esp=00cff57c ebp=00cff5a8 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll_77a90000!LdrpDoDebuggerBreak+0x2b:
77b3ed22 cc int 3
FAULTING_THREAD: 00000000000037cc
PROCESS_NAME: testC.exe
ERROR_CODE: (NTSTATUS) 0x4000001f - Win32 x86
EXCEPTION_CODE: (NTSTATUS) 0x4000001f (1073741855) - Win32 x86
EXCEPTION_PARAMETER1: 0000000000000000
NTGLOBALFLAG: 70
APPLICATION_VERIFIER_FLAGS: 0
APP: testc.exe
ANALYSIS_VERSION: 6.3.9600.17237 (debuggers(dbg).140716-0327) amd64fre
BUGCHECK_STR: APPLICATION_FAULT_APPLICATION_FAULT_ZEROED_STACK
PRIMARY_PROBLEM_CLASS: APPLICATION_FAULT
DEFAULT_BUCKET_ID: APPLICATION_FAULT
LAST_CONTROL_TRANSFER: from 0000000077b394e6 to 0000000077b3ed22
STACK_TEXT:
00cff5a8 77b394e6 f2b3a2ed 00b69000 00000000 ntdll_77a90000!LdrpDoDebuggerBreak+0x2b
00cff808 77ac2fe1 f2b3a285 00000000 00000000 ntdll_77a90000!LdrpInitializeProcess+0x1ba6
00cff860 77ac2ed1 00000000 00000000 00000000 ntdll_77a90000!_LdrpInitialize+0xba
00cff86c 00000000 00cff880 77a90000 00000000 ntdll_77a90000!LdrInitializeThunk+0x11
STACK_COMMAND: dt ntdll!LdrpLastDllInitializer BaseDllName ; dt ntdll!LdrpFailureData ; .cxr 0x0 ; kb
FOLLOWUP_IP:
ntdll_77a90000!LdrpDoDebuggerBreak+2b
77b3ed22 cc int 3
SYMBOL_STACK_INDEX: 0
SYMBOL_NAME: ntdll!LdrpDoDebuggerBreak+2b
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: ntdll_77a90000
IMAGE_NAME: ntdll.dll
DEBUG_FLR_IMAGE_TIMESTAMP: 35191cc1
FAILURE_BUCKET_ID: APPLICATION_FAULT_4000001f_ntdll.dll!LdrpDoDebuggerBreak
BUCKET_ID: APPLICATION_FAULT_APPLICATION_FAULT_ZEROED_STACK_ntdll!LdrpDoDebuggerBreak+2b
ANALYSIS_SOURCE: UM
FAILURE_ID_HASH_STRING: um:application_fault_4000001f_ntdll.dll!ldrpdodebuggerbreak
FAILURE_ID_HASH: {3541e160-89f9-c3a5-892f-80a0fe512d28}
Followup: MachineOwner
---------
由上,并没有提示要执行的命令,接下来执行以下kv,如下:
好像也没有我们的代码,这时候怎么办呢?
2.2 分析
2.2.1 查看一下堆栈分配情况
执行 !heap -s,如下:
只有一条信息,所以当然是分析这条信息了,如果存在很多条的话需要看分配最多的堆栈,如图红色框框的值,找出最大的几个值。
执行!heap -stat -h 00000000,如下:
如上图,找到了分配最多的堆栈块之后,可利用条件断点,获取分配该块内存时的栈信息。
设置断点如下:
bp ntdll!RtlAllocateHeap "j (poi(esp + c)=120) '';'gc'" // poi(esp + c) 表示取分配的堆块大小
之后执行g命令:
进程退出了,执行以下kv命令:
由上,我们就知道大概问题在哪了(虽然一开始看代码也知道),这个时候看一下提示附近的代码,发现一直在申请内存,但是没有释放操作,就很容易导致内存用完等情况的发生。