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