ZLUDA/ext/detours/samples/excep/firstexc.cpp

191 lines
6.5 KiB
C++
Vendored

//////////////////////////////////////////////////////////////////////////////
//
// 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.