Skip to content

Instantly share code, notes, and snippets.

@entdark
Created May 16, 2024 15:16
Show Gist options
  • Save entdark/4af06048cd237dd31071ffa3aa144c53 to your computer and use it in GitHub Desktop.
Save entdark/4af06048cd237dd31071ffa3aa144c53 to your computer and use it in GitHub Desktop.
Basic Crash Handler for Win32 API
#include <stdio.h>
#include <time.h>
#define PSAPI_VERSION 1
#include <Windows.h>
#include <Psapi.h>
#include <Dbghelp.h>
char* GetExceptionName(DWORD code)
{
switch(code)
{
case EXCEPTION_ACCESS_VIOLATION: return "Access Violation";
case EXCEPTION_DATATYPE_MISALIGNMENT: return "Datatype Misalignment";
case EXCEPTION_BREAKPOINT: return "Breakpoint";
case EXCEPTION_SINGLE_STEP: return "Single Step";
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "Array Bounds Exceeded";
case EXCEPTION_FLT_DENORMAL_OPERAND: return "Float Denormal Operand";
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "Float Divide By Zero";
case EXCEPTION_FLT_INEXACT_RESULT: return "Float Inexact Result";
case EXCEPTION_FLT_INVALID_OPERATION: return "Float Invalid Operation";
case EXCEPTION_FLT_OVERFLOW: return "Float Overflow";
case EXCEPTION_FLT_STACK_CHECK: return "Float Stack Check";
case EXCEPTION_FLT_UNDERFLOW: return "Float Underflow";
case EXCEPTION_INT_DIVIDE_BY_ZERO: return "Integer Divide By Zero";
case EXCEPTION_INT_OVERFLOW: return "Integer Overflow";
case EXCEPTION_PRIV_INSTRUCTION: return "Private Instruction";
case EXCEPTION_IN_PAGE_ERROR: return "In Page Error";
case EXCEPTION_ILLEGAL_INSTRUCTION: return "Illegal Instruction";
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "Non-continuable Exceptiopn";
case EXCEPTION_STACK_OVERFLOW: return "Stack Overflow";
case EXCEPTION_INVALID_DISPOSITION: return "Invalid Disposition";
case EXCEPTION_GUARD_PAGE: return "Guard Page";
case EXCEPTION_INVALID_HANDLE: return "Invalid Handle";
case 0xE06D7363: return "C++ Exception (using throw)";
default:
return "Unknown Exception";
}
}
void Win_PrintCallStack(FILE *output, HANDLE thread, CONTEXT* pContext)
{
BOOL result;
HANDLE process;
CONTEXT context;
STACKFRAME64 stack;
ULONG frame;
IMAGEHLP_SYMBOL64* symbol;
DWORD64 displacement;
DWORD64 moduleAddress;
DWORD baseOffset;
char symbolBuffer[sizeof(IMAGEHLP_SYMBOL64)+256];
char moduleName[128];
static char CrashLogFileName[128];
// redirect to standard output by default
if (!output)
output = stdout;
// trace stack for this thread by default
if (!thread)
thread = GetCurrentThread();
// use current context by default
if (!pContext)
{
memset( &context, 0, sizeof( context ) );
RtlCaptureContext( &context );
pContext = &context;
}
// stack info initialization
memset( &symbolBuffer, 0, sizeof( symbolBuffer ) );
symbol = (IMAGEHLP_SYMBOL64*)symbolBuffer;
memset( &stack, 0, sizeof( STACKFRAME64 ) );
process = GetCurrentProcess();
displacement = 0;
stack.AddrPC.Offset = pContext->Eip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = pContext->Esp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = pContext->Ebp;
stack.AddrFrame.Mode = AddrModeFlat;
// symbols inicialization (using Dbghelp.dll)
SymInitialize( process, NULL, TRUE );
frame = 0;
baseOffset = (DWORD)GetModuleHandle(NULL);
fprintf(output, "\n-----------------------------------\n");
fprintf(output, " Call Stack Trace \n");
fprintf(output, "-----------------------------------\n");
while( result = StackWalk64( IMAGE_FILE_MACHINE_I386, process, thread, &stack,
NULL, NULL, NULL, SymGetModuleBase64, NULL ) )
{
// get module name
moduleAddress = SymGetModuleBase64(process, stack.AddrPC.Offset);
GetModuleBaseName(process, (HMODULE) moduleAddress, moduleName, sizeof(moduleName));
// attempt to load symbol information (name/offset)
symbol->SizeOfStruct = sizeof( IMAGEHLP_SYMBOL64 );
symbol->MaxNameLength = 256;
SymGetSymFromAddr64( process, ( ULONG64 )stack.AddrPC.Offset, &displacement, symbol );
// with symbols
if ( symbol->Address && (stack.AddrPC.Offset >= symbol->Address) )
{
fprintf( output, "%s(%s+0x%llX) [0x%llX]\n",
moduleName, symbol->Name, stack.AddrPC.Offset-symbol->Address, stack.AddrPC.Offset );
}
else
{
fprintf( output, "%s [0x%llX]\n",
moduleName, stack.AddrPC.Offset );
}
++frame;
}
}
LONG Win_Handler(LPEXCEPTION_POINTERS p)
{
HANDLE process, thread;
static char ProcessName[128],ModuleName[128];
static char CrashLogFileName[128];
static char CrashLogFileMiniDumpName[128];
time_t rawtime;
struct tm * timeinfo;
FILE* CrashLogFile;
DWORD64 moduleAddress;
HANDLE hDumpFile = NULL;
process = GetCurrentProcess();
thread = GetCurrentThread();
// symbols inicialization (using Dbghelp.dll)
SymInitialize( process, NULL, TRUE );
// get process name
GetModuleFileName(NULL,ProcessName,sizeof(ProcessName));
// get module name
moduleAddress = SymGetModuleBase64(process, (DWORD64)p->ExceptionRecord->ExceptionAddress);
GetModuleBaseName(GetCurrentProcess(), (HMODULE) moduleAddress, ModuleName, sizeof(ModuleName));
// generate crash log file name
time ( &rawtime );
timeinfo = localtime ( &rawtime );
strftime(CrashLogFileName, sizeof(CrashLogFileName), "crash_log_%Y-%m-%d_%H-%M-%S.log", timeinfo);
//Before we possibly fuck any of the stack or heap in the middle of a you know - crash - save the state to a minidump
// open crash log file
CrashLogFile = fopen(CrashLogFileName,"w");
fprintf(CrashLogFile, "Process File Name: %s\n", ProcessName );
fprintf(CrashLogFile, "Exception Code: 0x%08X (%s)\n",
p->ExceptionRecord->ExceptionCode, GetExceptionName(p->ExceptionRecord->ExceptionCode));
fprintf(CrashLogFile, "Exception Address: 0x%08X (%s+0x%X)\n",
p->ExceptionRecord->ExceptionAddress,ModuleName,(DWORD)p->ExceptionRecord->ExceptionAddress - moduleAddress);
fprintf(CrashLogFile, "\n-----------------------------------\n");
fprintf(CrashLogFile, " Register Dump \n");
fprintf(CrashLogFile, "-----------------------------------\n");
fprintf(CrashLogFile, "General Purpose & Control Registers:\n");
fprintf(CrashLogFile, "EAX: 0x%08X, EBX: 0x%08X, ECX: 0x%08X\n",
p->ContextRecord->Eax, p->ContextRecord->Ebx, p->ContextRecord->Ecx );
fprintf(CrashLogFile, "EDX: 0x%08X, EBP: 0x%08X, EDI: 0x%08X\n",
p->ContextRecord->Edx, p->ContextRecord->Ebp, p->ContextRecord->Edi );
fprintf(CrashLogFile, "EIP: 0x%08X, ESI: 0x%08X, ESP: 0x%08X\n",
p->ContextRecord->Eip, p->ContextRecord->Esi, p->ContextRecord->Esp );
fprintf(CrashLogFile, "\nSegment Registers:\n");
fprintf(CrashLogFile, "CS: 0x%08X, DS: 0x%08X, ES: 0x%08X\n",
p->ContextRecord->SegCs, p->ContextRecord->SegDs, p->ContextRecord->SegEs );
fprintf(CrashLogFile, "FS: 0x%08X, GS: 0x%08X, SS: 0x%08X\n",
p->ContextRecord->SegFs, p->ContextRecord->SegGs, p->ContextRecord->SegSs );
Win_PrintCallStack(CrashLogFile, thread, p->ContextRecord);
// close crash log file
fclose(CrashLogFile);
return EXCEPTION_EXECUTE_HANDLER;
}
void InitUnhandledExceptionFilter()
{
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)&Win_Handler);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment