diff options
Diffstat (limited to 'samples/excep/firstexc.cpp')
-rw-r--r-- | samples/excep/firstexc.cpp | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/samples/excep/firstexc.cpp b/samples/excep/firstexc.cpp new file mode 100644 index 0000000..4222ba8 --- /dev/null +++ b/samples/excep/firstexc.cpp @@ -0,0 +1,191 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Detours Test Program (firstexc.cpp of firstexc.lib) +// +// Microsoft Research Detours Package +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// For more information on exception handling, see "A Crash Course on the +// Depths of Win32 Structured Exception Handling," by Matt Pietrek in the +// January 1997 issue of Microsoft Systems Journal. +// +#include <stdio.h> +#include <windows.h> +#include "detours.h" +#include "firstexc.h" + +#if _MSC_VER > 1000 +#pragma warning(disable: 4740) +#endif + +////////////////////////////////////////////////////////////////////////////// +// +static BOOL s_bExceptionDetourInstalled = FALSE; +static LPTOP_LEVEL_EXCEPTION_FILTER s_pFirstChanceFilter = NULL; + +ULONG (NTAPI *Real_NtContinue)(IN PCONTEXT ContextRecord, + IN BOOLEAN TestAlerts) = NULL; + +VOID (NTAPI *Real_KiUserExceptionDispatcher)(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT ContextFrame) = NULL; + +////////////////////////////////////////////////////////////////////////////// +// +// This function effectively removes all try..catch frames for the current +// stack. It forces all exceptions to be treated as unhandled exceptions. +// +#pragma warning(push) +#pragma warning(disable: 4733) +static VOID WINAPI RemoveAllExceptionHandlers(VOID) +{ + // The basic, OS defined exception frame + struct EXCEPTION_REGISTRATION + { + EXCEPTION_REGISTRATION* prev; + FARPROC handler; + }; + + EXCEPTION_REGISTRATION * pVCExcRec = NULL; + EXCEPTION_REGISTRATION * pLastGood = NULL; + + __asm mov eax, FS:[0]; + __asm mov [pVCExcRec], eax; + + for (pLastGood = pVCExcRec; (ULONG)pVCExcRec != ~0ul; ) { + if ((ULONG)pVCExcRec >= 0x30000000) + break; + + pLastGood = pVCExcRec; + pVCExcRec = (EXCEPTION_REGISTRATION *)(pVCExcRec->prev); + } + + __asm mov eax, [pLastGood]; + __asm mov FS:[0], eax; +} +#pragma warning(pop) + +////////////////////////////////////////////////////////////////////////////// +// Routine Description: +// +// This routine is entered on return from kernel mode to dispatch a user +// mode exception. If a frame based handler handles the exception, then +// the execution is continued. Else last chance processing is performed. +// +// NOTE: This procedure is not called, but rather dispatched to. +// It depends on there not being a return address on the stack +// (assumption w.r.t. argument offsets.) +// +// Arguments: +// ExceptionRecord (esp+0) - Supplies a pointer to an exception record. +// ContextRecord (esp+4) - Supplies a pointer to a context frame. +// +// Return Value: +// None. +// +static VOID __declspec(naked) NTAPI +Detour_KiUserExceptionDispatcher(PEXCEPTION_RECORD pExceptRec, + CONTEXT *pContext) +{ + __asm { + xor eax, eax ; // Create fake return address on stack. + push eax ; // (Generally, we are called by the kernel.) + + push ebp ; // Prolog + mov ebp, esp ; + sub esp, __LOCAL_SIZE ; + } + + LPTOP_LEVEL_EXCEPTION_FILTER pFirstChanceFilter; + EXCEPTION_POINTERS ep; + DWORD dwReturn; + DWORD dwError; + + ep.ExceptionRecord = pExceptRec; + ep.ContextRecord = pContext; + pFirstChanceFilter = s_pFirstChanceFilter; + dwReturn = EXCEPTION_CONTINUE_SEARCH; + dwError = 0; + + if (s_pFirstChanceFilter) { + dwReturn = pFirstChanceFilter(&ep); + } + + if (dwReturn == EXCEPTION_CONTINUE_EXECUTION) { + dwError = Real_NtContinue(pContext, 0); + // This call should *NEVER* return. If it does, we want to fail to the debugger. + RemoveAllExceptionHandlers(); + } + + if (dwReturn == EXCEPTION_EXECUTE_HANDLER) { // Special: Call debugger. + RemoveAllExceptionHandlers(); + } + + __asm { + mov ebx, pExceptRec ; + mov ecx, pContext ; + push ecx ; + push ebx ; + mov eax, [Real_KiUserExceptionDispatcher]; + jmp eax ; + ; + ; The above code should never return. + ; + int 3 ; // Break! + ; + mov esp, ebp ; // Epilog + pop ebp ; + ret ; + } +} + +////////////////////////////////////////////////////////////////////////////// +// +// Set the first-chance exception filter. +// +// Returns the pointer to the last first-chance exception filter if there +// was one. If this is the first first-chance exception filter, installs +// the necessary detour and acquires the appropriate function pointers. +// If the parameter is NULL, first-chance exception filtering is disabled. +// +// A first-chance exception filter should always return one of three +// possible codes: +// +// EXCEPTION_CONTINUE_SEARCH: +// The exception was not handled by this filter; continue the +// search for the appropriate exception handler. +// +// EXCEPTION_CONTINUE_EXECUTION: +// The exception was handled by this filter; continue execution +// at the point were the exception was thrown. +// +// EXCEPTION_EXECUTE_HANDLER: +// Drastic failure in the exception filter. Process the +// exception as if no exception handlers were installed. +// (i.e. Give the user a chance to invoke the debugger.) +// +LPTOP_LEVEL_EXCEPTION_FILTER WINAPI +DetourFirstChanceExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER pNewFirstChanceFilter) +{ + if (!s_bExceptionDetourInstalled) { + s_bExceptionDetourInstalled = TRUE; + + Real_NtContinue = (ULONG (NTAPI *)(IN PCONTEXT, IN BOOLEAN)) + DetourFindFunction("ntdll.dll", "NtContinue"); + Real_KiUserExceptionDispatcher = + (VOID (NTAPI *)(IN PEXCEPTION_RECORD, IN PCONTEXT)) + DetourFindFunction("ntdll.dll", "KiUserExceptionDispatcher"); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + DetourAttach(&(PVOID&)Real_KiUserExceptionDispatcher, + Detour_KiUserExceptionDispatcher); + DetourTransactionCommit(); + } + + LPTOP_LEVEL_EXCEPTION_FILTER pOldFirstChanceFilter = s_pFirstChanceFilter; + s_pFirstChanceFilter = pNewFirstChanceFilter; + return pOldFirstChanceFilter; +} +// +///////////////////////////////////////////////////////////////// End of File. |