"principle"
When the Windows program encounters an exception, no try-catch or try-catch can catch the exception, the program will automatically exit, if there is no dump file at this time, we do not get any program exit information. An exception handling callback function that is registered in the program is pre-invoked before the Windows program exits abnormally (default is no setting), as long as we call the MiniDumpWriteDump function in this callback function to generate the dump file we want.
Achieve
1. Call SetUnhandledExceptionFilter to register a custom exception handling callback function
SetUnhandledExceptionFilter (Myunhandledexceptionfilter);
2.CreateFile Create dump file, call MiniDumpWriteDump function to write exception information to dump file
Achieve
#pragma once #include <windows.h>class cminidumper{public:static HRESULT Createin Stance (); Static HRESULT releaseinstance ();p ublic:long writeminidump (_exception_pointers *pexceptioninfo);p rivate:void SetM Inidumpfilename (void); BOOL GetImpersonationToken (handle* phtoken); BOOL Enableprivilege (LPCTSTR pszpriv, HANDLE htoken, token_privileges* ptpold); BOOL Restoreprivilege (HANDLE htoken, token_privileges* ptpold);p rivate:cminidumper (); virtual ~cminidumper (void); Private:tcharm_szminidumppath[max_path]; Tcharm_szapppath[max_path];};
#include "stdafx.h" #include <windows.h> #include <stdio.h> #include <assert.h> #include <time.h > #include <tchar.h> #include <dbghelp.h> #include "miniDump.h" #ifdef UNICODE #define _tcssprintf wsprintf #define Tcsplitpath _wsplitpath#else #define _TCSSPRINTF sprintf #define Tcsplitpath _splitpath#endif//- ----------------------------------------------------------------------------//globals//------------------------ -----------------------------------------------------cminidumper *gs_pminidumper = NULL; Lpcritical_section gs_pcriticalsection = null;//----------------------------------------------------------------- ------------//apis//-----------------------------------------------------------------------------//Based on Dbghelp.htypedef BOOL (WINAPI *minidumpwritedump) (HANDLE hprocess,dword dwpid,handle hfile,minidump_type DumpType, CONST pminidump_exception_information exceptionparam,const pminidump_user_stream_information UserStreamPaRam,const pminidump_callback_information Callbackparam); BOOL isdatasectionneeded (const wchar* pmodulename) {if (Pmodulename = = 0) {return FALSE;} WCHAR Szfilename[_max_fname] = {0};_wsplitpath (pmodulename, NULL, NULL, szFileName, NULL); if (_wcsicmp (szFileName, L " Ntdll ") = = 0) return True;return FALSE;} BOOL WINAPI minidumpcallback (PVOID pparam,const pminidump_callback_input pinput,pminidump_callback_output pOut Put) {if (Pinput = = 0 | | poutput = = 0) return False;switch (pinput->callbacktype) {case Modulecallback:if (poutput ->modulewriteflags & modulewritedataseg) {if (! Isdatasectionneeded (Pinput->module.fullpath)) Poutput->modulewriteflags &= (~MODULEWRITEDATASEG); } return true;case includemodulecallback:case includethreadcallback:case threadcallback:case ThreadExCallba Ck:return True;default:;} return FALSE;} -----------------------------------------------------------------------------//Name:unhandledexcePtionhandler ()//Desc:call-back filter function for unhandled exceptions//------------------------------------------ -----------------------------------LONG WINAPI Unhandledexceptionhandler (_exception_pointers *pexceptioninfo) {if ( NULL = = Gs_pminidumper) return exception_continue_search; Return Gs_pminidumper->writeminidump (Pexceptioninfo);} Once this function is called successfully, the call to SetUnhandledExceptionFilter will not be valid void Disablesetunhandledexceptionfilter () {hmodule hmodule = L Oadlibrary (L "kernel32.dll"); void* paddr = (void*) GetProcAddress (hmodule, "SetUnhandledExceptionFilter"); if (paddr) {unsigned char code[16] = {0}; int size = 0; code[size++] = 0x33; code[size++] = 0xC0; code[size++] = 0xC2; code[size++] = 0x04; code[size++] = 0x00; DWORD dwoldflag = 0; DWORD dwtempflag = 0; VirtualProtect (paddr, size, page_readwrite, &dwoldflag); WriteProcessMemory (GetCurrentProcess (), PADDR, code, Size, NULL); VirtualProtect (paddr, size, Dwoldflag, &dwtempflag); } freelibrary (hmodule);} -----------------------------------------------------------------------------//Name:createinstance ()//DESC: Instanse gs_pminidumper//-----------------------------------------------------------------------------HRESULT Cminidumper::createinstance () {if (NULL = = gs_pminidumper) {gs_pminidumper = new cminidumper (); } if (NULL = = gs_pcriticalsection) {gs_pcriticalsection = new critical_section; InitializeCriticalSection (gs_pcriticalsection); } return (S_OK);} -----------------------------------------------------------------------------//Name:releaseinstance ()//DESC: Release gs_pminidumper//-----------------------------------------------------------------------------HRESULT Cminidumper::releaseinstance () {if (NULL! = gs_pminidumper) {delete gs_pminidumper; Gs_pminidumper = NULL; } if (NULL! = gs_pcriticalsection) {deletecriticalsection (gs_pcriticalsection); Gs_pcriticalsection = NULL; } return (S_OK);} -----------------------------------------------------------------------------//Name:cminidumper ()//DESC: constructor//-----------------------------------------------------------------------------Cminidumper:: Cminidumper () {//Enables the application to replace the top-level exception handlers for each process and thread: SetUnhandledExceptionFilter (Unhandledexceptionhandler);D Isablesetunhandledexceptionfilter ();} -----------------------------------------------------------------------------//Name: ~cminidumper ()//DESC: destructor//-----------------------------------------------------------------------------cminidumper::~ Cminidumper (void) {}//-----------------------------------------------------------------------------//Name: Setminidumpfilename ()//DESC://----------------------------------------------------------------------------- void Cminidumper::setminidumpfilename (void) {time_t currenttime;time (¤ttime); _tcssprintf (M_szminiDumppath, _t ("%s.%ld.dmp"), M_szapppath, currenttime);} -----------------------------------------------------------------------------//Name:getimpersonationtoken ()/ /Desc:the method acts as a potential workaround for the fact, the//current thread could not have a token Assig Ned to it, and if isn't, the//process token is received.//---------------------------------------------------------- -------------------BOOL Cminidumper::getimpersonationtoken (handle* phtoken) {*phtoken = Null;if (! OpenThreadToken (GetCurrentThread (), Token_query | Token_adjust_privileges, TRUE, Phtoken)) {if (GetLastError () = = Error_no_token) {//NO impersonation TOKEN for the current T Hread is available. Let's go for the process token instead.if (! OpenProcessToken (GetCurrentProcess (), Token_query | Token_adjust_privileges, Phtoken)) return FALSE;} Elsereturn FALSE;} return TRUE;} -----------------------------------------------------------------------------//Name:enableprivilege ()//DESC: Since A MiniDump contains a lot of meta-data on the OS and//application state at the time of the dump, it's a rathe R Privileged//operation. This means we need to set the SeDebugPrivilege to is able//to call minidumpwritedump.//--------------------------- --------------------------------------------------BOOL Cminidumper::enableprivilege (lpctstr pszpriv, HANDLE htoken , token_privileges* ptpold) {boolbok = FALSE; TOKEN_PRIVILEGESTP;TP. Privilegecount = 1;tp. Privileges[0]. Attributes = Se_privilege_enabled;bok = Lookupprivilegevalue (0, Pszpriv, &TP. Privileges[0]. LUID); if (bok) {DWORD cbold = sizeof (*ptpold); bOk = AdjustTokenPrivileges (Htoken, FALSE, &TP, Cbold, Ptpold, &cbol d);} Return (BOk && (error_not_all_assigned! = GetLastError ()));} -----------------------------------------------------------------------------//Name:restoreprivilege ()//Desc ://-----------------------------------------------------------------------------BOOL Cminidumper::restorePrivilege (HANDLE htoken, token_privileges* ptpold) {BOOL bOk = AdjustTokenPrivileges (Htoken, FALSE, ptpold, 0, NULL, NULL) ; return (BOk && (error_not_all_assigned! = GetLastError ()));} -----------------------------------------------------------------------------//Name:writeminidump ()//DESC:// -----------------------------------------------------------------------------LONG Cminidumper::writeminidump (_ Exception_pointers *pexceptioninfo) {longretval= exception_continue_search; Handlehimpersonationtoken = Null;if (! GetImpersonationToken (&himpersonationtoken)) return false;//you has to find the right dbghelp.dll. Look next to the EXE first since the one in System32 might is old (Win2K) hmodule hdll= null;if (GetModuleFileName (NULL, M_szapppath, _max_path)) {wchar_t Szdir[_max_dir] = {0}; Tcharszdbghelppath[max_path] = {0}; _wsplitpath (M_szapppath, NULL, szdir, NULL, NULL); _tcscpy (Szdbghelppath, szdir); _tcscat (Szdbghelppath, _t("Dbghelp. DLL ")); hDLL =:: LoadLibrary (Szdbghelppath);} if (hDLL = = NULL) {//If we haven ' t found it yet-try one more Time.hdll =:: LoadLibrary (_t ("Dbghelp". DLL ")); if (hdll) {//Get the address of the MiniDumpWriteDump function, which writes//User-mode mini-dump information to a speci fied file. MiniDumpWriteDump minidumpwritedump = (minidumpwritedump):: GetProcAddress (hDLL, "minidumpwritedump"); if ( MiniDumpWriteDump! = NULL) {setminidumpfilename ();//Create the mini-dump file ... HANDLE hfile =:: CreateFile (M_szminidumppath,generic_write,file_share_write,null,create_always,file_attribute_ Normal,null); if (hfile! = invalid_handle_value) {_minidump_exception_information exinfo; Exinfo.threadid =:: GetCurrentThreadID (); Exinfo.exceptionpointers = Pexceptioninfo; Exinfo.clientpointers = NULL; Minidump_callback_information MCI;MCI. Callbackroutine = (minidump_callback_routine) minidumpcallback;mci. Callbackparam = 0;//We need the SeDebugPrivilege to being able to run Minidumpwritedumptoken_privileges Tp;boOL bprivilegeenabled = Enableprivilege (Se_debug_name, Himpersonationtoken, &TP); BOOL bok;//DBGHELP.dll is isn't thread-safe, so we need to restrict access ... EnterCriticalSection (gs_pcriticalsection); {//Write out of the mini-dump data to the File...bok = MiniDumpWriteDump (GetCurrentProcess (), GetCurrentProcessId (), hfile, Minidumpnormal, (NULL = = pexceptioninfo)? (NULL): (&exinfo), NULL,&MCI);} LeaveCriticalSection (gs_pcriticalsection);//Restore the privileges when Doneif (bprivilegeenabled) Restoreprivilege ( Himpersonationtoken, &TP); if (bOk) {retval = Exception_execute_handler;}::closehandle (hfile);}}} FreeLibrary (hDLL); if (NULL! = pexceptioninfo) {terminateprocess (getcurrentprocess (), 0); } return retval;}
Test
Dumper.cpp: Defines the entry point of the console application. #include "stdafx.h" #include "miniDump.h" extern cminidumper *gs_pminidumper;int _tmain (int argc, _tchar* argv[]) { Cminidumper::createinstance (); char *p = null;*p = ' B ';/*__try{*p = ' B ';} __except (Gs_pminidumper->writeminidump (GetExceptionInformation ()), exception_continue_execution) {}*/}
The generated DMP file
Sh
C + + Records dumpfile when a Windows program crashes