192 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			192 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  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.
							 |