Figure 14: KiUserExceptionDispatcher Pseudocode
KiUserExceptionDispatcher( PEXCEPTION_RECORD pExcptRec, CONTEXT * pContext )
{
DWORD retValue;
// Note: If the exception is handled, RtlDispatchException() never returns
if ( RtlDispatchException( pExceptRec, pContext ) )
retValue = NtContinue( pContext, 0 );
else
retValue = NtRaiseException( pExceptRec, pContext, 0 );
EXCEPTION_RECORD excptRec2;
excptRec2.ExceptionCode = retValue;
excptRec2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
excptRec2.ExceptionRecord = pExcptRec;
excptRec2.NumberParameters = 0;
RtlRaiseException( &excptRec2 );
}
int RtlDispatchException( PEXCEPTION_RECORD pExcptRec, CONTEXT * pContext )
{
DWORD stackUserBase;
DWORD stackUserTop;
PEXCEPTION_REGISTRATION pRegistrationFrame;
DWORD hLog;
// Get stack boundaries from FS:[4] and FS:[8]
RtlpGetStackLimits( &stackUserBase, &stackUserTop );
pRegistrationFrame = RtlpGetRegistrationHead();
while ( -1 != pRegistrationFrame )
{
PVOID justPastRegistrationFrame = &pRegistrationFrame + 8;
if ( stackUserBase > justPastRegistrationFrame )
{
pExcptRec->ExceptionFlags |= EH_STACK_INVALID;
return DISPOSITION_DISMISS; // 0
}
if ( stackUsertop < justPastRegistrationFrame )
{
pExcptRec->ExceptionFlags |= EH_STACK_INVALID;
return DISPOSITION_DISMISS; // 0
}
if ( pRegistrationFrame & 3 ) // Make sure stack is DWORD aligned
{
pExcptRec->ExceptionFlags |= EH_STACK_INVALID;
return DISPOSITION_DISMISS; // 0
}
if ( someProcessFlag )
{
// Doesn't seem to do a whole heck of a lot.
hLog = RtlpLogExceptionHandler( pExcptRec, pContext, 0,
pRegistrationFrame, 0x10 );
}
DWORD retValue, dispatcherContext;
retValue= RtlpExecuteHandlerForException(pExcptRec, pRegistrationFrame,
pContext, &dispatcherContext,
pRegistrationFrame->handler );
// Doesn't seem to do a whole heck of a lot.
if ( someProcessFlag )
RtlpLogLastExceptionDisposition( hLog, retValue );
if ( 0 == pRegistrationFrame )
{
pExcptRec->ExceptionFlags &= ~EH_NESTED_CALL; // Turn off flag
}
EXCEPTION_RECORD excptRec2;
DWORD yetAnotherValue = 0;
if ( DISPOSITION_DISMISS == retValue )
{
if ( pExcptRec->ExceptionFlags & EH_NONCONTINUABLE )
{
excptRec2.ExceptionRecord = pExcptRec;
excptRec2.ExceptionNumber = STATUS_NONCONTINUABLE_EXCEPTION;
excptRec2.ExceptionFlags = EH_NONCONTINUABLE;
excptRec2.NumberParameters = 0
RtlRaiseException( &excptRec2 );
}
else
return DISPOSITION_CONTINUE_SEARCH;
}
else if ( DISPOSITION_CONTINUE_SEARCH == retValue )
{
}
else if ( DISPOSITION_NESTED_EXCEPTION == retValue )
{
pExcptRec->ExceptionFlags |= EH_EXIT_UNWIND;
if ( dispatcherContext > yetAnotherValue )
yetAnotherValue = dispatcherContext;
}
else // DISPOSITION_COLLIDED_UNWIND
{
excptRec2.ExceptionRecord = pExcptRec;
excptRec2.ExceptionNumber = STATUS_INVALID_DISPOSITION;
excptRec2.ExceptionFlags = EH_NONCONTINUABLE;
excptRec2.NumberParameters = 0
RtlRaiseException( &excptRec2 );
}
pRegistrationFrame = pRegistrationFrame->prev; // Go to previous frame
}
return DISPOSITION_DISMISS;
}
_RtlpExecuteHandlerForException: // Handles exception (first time through)
MOV EDX,XXXXXXXX
JMP ExecuteHandler
RtlpExecutehandlerForUnwind: // Handles unwind (second time through)
MOV EDX,XXXXXXXX
int ExecuteHandler( PEXCEPTION_RECORD pExcptRec
PEXCEPTION_REGISTRATION pExcptReg
CONTEXT * pContext
PVOID pDispatcherContext,
FARPROC handler ) // Really a ptr to an _except_handler()
// Set up an EXCEPTION_REGISTRATION, where EDX points to the
// appropriate handler code shown below
PUSH EDX
PUSH FS:[0]
MOV FS:[0],ESP
// Invoke the exception callback function
EAX = handler( pExcptRec, pExcptReg, pContext, pDispatcherContext );
// Remove the minimal EXCEPTION_REGISTRATION frame
MOV ESP,DWORD PTR FS:[00000000]
POP DWORD PTR FS:[00000000]
return EAX;
}
Exception handler used for _RtlpExecuteHandlerForException:
{
// If unwind flag set, return DISPOSITION_CONTINUE_SEARCH, else
// assign pDispatcher context and return DISPOSITION_NESTED_EXCEPTION
return pExcptRec->ExceptionFlags & EXCEPTION_UNWIND_CONTEXT
? DISPOSITION_CONTINUE_SEARCH
: *pDispatcherContext = pRegistrationFrame->scopetable,
DISPOSITION_NESTED_EXCEPTION;
}
Exception handler used for _RtlpExecuteHandlerForUnwind:
{
// If unwind flag set, return DISPOSITION_CONTINUE_SEARCH, else
// assign pDispatcher context and return DISPOSITION_COLLIDED_UNWIND
return pExcptRec->ExceptionFlags & EXCEPTION_UNWIND_CONTEXT
? DISPOSITION_CONTINUE_SEARCH
: *pDispatcherContext = pRegistrationFrame->scopetable,
DISPOSITION_COLLIDED_UNWIND;
}