参考网络资料及源码整理:
头文件
#ifndef _H_WIN_DUMP_H_
#define _H_WIN_DUMP_H_
#include
#include
#pragma comment( lib, "DbgHelp" )
//
//DO NOT CARE THINGS
TCHAR DUMP_FILE_NAME[512] = {0};
#if defined _M_X64 || defined _M_IX86
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI
MyDummySetUnhandledExceptionFilter(
LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
{
return NULL;
}
#else
#error "This code works only for x86 and x64!"
#endif
BOOL PreventSetUnhandledExceptionFilter()
{
HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
if (hKernel32 == NULL) return FALSE;
void *pOrgEntry = GetProcAddress(hKernel32,
"SetUnhandledExceptionFilter");
if(pOrgEntry == NULL) return FALSE;
DWORD dwOldProtect = 0;
SIZE_T jmpSize = 5;
#ifdef _M_X64
jmpSize = 13;
#endif
BOOL bProt = VirtualProtect(pOrgEntry, jmpSize,
PAGE_EXECUTE_READWRITE, &dwOldProtect);
BYTE newJump[20];
void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
#ifdef _M_IX86
DWORD dwOrgEntryAddr = (DWORD) pOrgEntry;
dwOrgEntryAddr += jmpSize; // add 5 for 5 op-codes for jmp rel32
DWORD dwNewEntryAddr = (DWORD) pNewFunc;
DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
// JMP rel32: Jump near, relative, displacement relative to next instruction.
newJump[0] = 0xE9; // JMP rel32
memcpy(&newJump[1], &dwRelativeAddr, sizeof(pNewFunc));
#elif _M_X64
// We must use R10 or R11, because these are "scratch" registers
// which need not to be preserved accross function calls
// For more info see: Register Usage for x64 64-Bit
// http://msdn.microsoft.com/en-us/library/ms794547.aspx
// Thanks to Matthew Smith!!!
newJump[0] = 0x49; // MOV R11, ...
newJump[1] = 0xBB; // ...
memcpy(&newJump[2], &pNewFunc, sizeof (pNewFunc));
//pCur += sizeof (ULONG_PTR);
newJump[10] = 0x41; // JMP R11, ...
newJump[11] = 0xFF; // ...
newJump[12] = 0xE3; // ...
#endif
SIZE_T bytesWritten;
BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
pOrgEntry, newJump, jmpSize, &bytesWritten);
if (bProt != FALSE)
{
DWORD dwBuf;
VirtualProtect(pOrgEntry, jmpSize, dwOldProtect, &dwBuf);
}
return bRet;
}
LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
{
//创建dump文件
HANDLE lhDumpFile = CreateFile((LPCTSTR)DUMP_FILE_NAME, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL ,NULL);
MINIDUMP_EXCEPTION_INFORMATION loExceptionInfo;
loExceptionInfo.ExceptionPointers = ExceptionInfo;
loExceptionInfo.ThreadId = GetCurrentThreadId();
loExceptionInfo.ClientPointers = TRUE;
//捕获异常写入dump文件
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),lhDumpFile, MiniDumpNormal, &loExceptionInfo, NULL, NULL);
CloseHandle(lhDumpFile);
return EXCEPTION_EXECUTE_HANDLER;
}
//Interface
BOOL SetMyUnhandledExceptionFilter(TCHAR* dumpName)
{
memset(DUMP_FILE_NAME,0,sizeof(DUMP_FILE_NAME));
_tcscpy_s(DUMP_FILE_NAME,sizeof(DUMP_FILE_NAME),dumpName);
//为未捕获且引起崩溃异常注册捕获
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
//防止编译器再次注册捕获,编译器默认会注册SetUnhandledExceptionFilter
return PreventSetUnhandledExceptionFilter();
}
#endif
// test123.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "winDump.h"
int _tmain(int argc, _TCHAR* argv[])
{
SetMyUnhandledExceptionFilter(L"myTest.dmp");
char* p=NULL;
memcpy(p,"this is just dump test",5);
return 0;
}
运行结果:
启动调试:
用编译器调试(VS):
1.将dmp拷贝至当时编译的电脑上(如果不在同一台电脑,调试时要指定对应版本的源码 )
2.将 test123.exe 和 test123.pdb 及 dmp文件放置同一个文件夹中
3.确保原本的编译代码没有改变过,及要有对应版本的代码,
4.F5启动调试,此时就可以在源码中看到崩溃点了。
用windbg调试:
没试过。
VS调试截图如下: