[NTOS:KE:X64][NTDLL:X64] Implement KiUserExceptionDispatcher and fix KiDispatchExceptionToUser

This commit is contained in:
Timo Kreuzer 2019-04-18 16:41:48 +02:00
parent 1bfacf06f7
commit 2a8c680dbe
3 changed files with 151 additions and 24 deletions

View file

@ -107,11 +107,125 @@ StatusRaise:
.ENDP
/*
BOOLEAN
NTAPI
RtlDispatchException(
_In_ PEXCEPTION_RECORD ExceptionRecord,
_In_ PCONTEXT ContextRecord);
*/
EXTERN RtlDispatchException:PROC
/*
NTSTATUS
NTAPI
ZwContinue(
_In_ PCONTEXT Context,
_In_ BOOLEAN TestAlert);
*/
EXTERN ZwContinue:PROC
/*
NTSTATUS
NTAPI
ZwRaiseException(
_In_ PEXCEPTION_RECORD ExceptionRecord,
_In_ PCONTEXT Context,
_In_ BOOLEAN SearchFrames);
*/
EXTERN ZwRaiseException:PROC
/*
VOID
NTAPI
RtlRaiseStatus(
_In_ PEXCEPTION_RECORD ExceptionRecord);
*/
EXTERN RtlRaiseException:PROC
/*
VOID
KiUserExceptionDispatcher(
CONTEXT ContextRecord<rcx>,
PEXCEPTION_RECORD ExceptionRecord<rdx>);
This function is called with the following stack layout:
CONTEXT ContextRecord <- RSP, RCX
EXCEPTION_RECORD ExceptionRecord <- RDX
ULONG64 Alignment
MACHINE_FRAME MachineFrame
*/
PUBLIC KiUserExceptionDispatcher
.PROC KiUserExceptionDispatcher
.endprolog
int 3
; The stack is set up with a KUSER_EXCEPTION_STACK
; The frame ends with a MACHINE_FRAME.
.PUSHFRAME
; This is for the alignment, EXCEPTION_RECORD and CONTEXT
.ALLOCSTACK 8 + EXCEPTION_RECORD_LENGTH + CONTEXT_FRAME_LENGTH
.ENDPROLOG
/* Clear direction flag */
cld
/* Dispatch the exception */
call RtlDispatchException
/* Check for success */
or al, al
jz RaiseException
/* We're fine, continue execution */
lea rcx, [rsp] ; ContextRecord
mov dl, 0 ; TestAlert
call ZwContinue
/* Exit */
jmp Exit
RaiseException:
/* Raise the exception */
lea rcx, [rsp + CONTEXT_FRAME_LENGTH] ; ExceptionRecord
lea rdx, [rsp] ; ContextRecord
xor r8, r8
call ZwRaiseException
Exit:
lea rcx, [rsp + CONTEXT_FRAME_LENGTH] ; ExceptionRecord
mov rdx, rax
call KiUserExceptionDispatcherNested
ret
.ENDP
/*
VOID
KiUserExceptionDispatcherNested(
_In_ ExceptionRecord<rcx>,
_In_ Status<edx>
)
*/
.PROC KiUserExceptionDispatcherNested
/* Allocate space for the nested exception record */
sub rsp, EXCEPTION_RECORD_LENGTH
.ALLOCSTACK EXCEPTION_RECORD_LENGTH
.ENDPROLOG
/* Set it up */
mov dword ptr [rsp + ErNumberParameters], 0
mov dword ptr [rsp + ErExceptionFlags], EXCEPTION_NONCONTINUABLE
mov [rsp + ErExceptionRecord], rcx
mov [rsp + ErExceptionCode], edx
/* Raise the exception */
mov rcx, rsp
call RtlRaiseException
/* Cleanup stack and return */
add rsp, EXCEPTION_RECORD_LENGTH
ret
.ENDP
END

View file

@ -100,10 +100,8 @@ KiDispatchExceptionToUser(
IN PEXCEPTION_RECORD ExceptionRecord)
{
EXCEPTION_RECORD LocalExceptRecord;
ULONG Size;
ULONG64 UserRsp;
PCONTEXT UserContext;
PEXCEPTION_RECORD UserExceptionRecord;
PKUSER_EXCEPTION_STACK UserStack;
/* Make sure we have a valid SS */
if (TrapFrame->SegSs != (KGDT64_R3_DATA | RPL_MASK))
@ -115,27 +113,29 @@ KiDispatchExceptionToUser(
ExceptionRecord = &LocalExceptRecord;
}
/* Calculate the size of the exception record */
Size = FIELD_OFFSET(EXCEPTION_RECORD, ExceptionInformation) +
ExceptionRecord->NumberParameters * sizeof(ULONG64);
/* Get new stack pointer and align it to 16 bytes */
UserRsp = (Context->Rsp - Size - sizeof(CONTEXT)) & ~15;
UserRsp = (Context->Rsp - sizeof(KUSER_EXCEPTION_STACK)) & ~15;
/* Get pointers to the usermode context and exception record */
UserContext = (PVOID)UserRsp;
UserExceptionRecord = (PVOID)(UserRsp + sizeof(CONTEXT));
/* Get pointer to the usermode context, exception record and machine frame */
UserStack = (PKUSER_EXCEPTION_STACK)UserRsp;
/* Set up the user-stack */
_SEH2_TRY
{
/* Probe stack and copy Context */
ProbeForWrite(UserContext, sizeof(CONTEXT), sizeof(ULONG64));
*UserContext = *Context;
/* Probe the user stack frame and zero it out */
ProbeForWrite(UserStack, sizeof(*UserStack), TYPE_ALIGNMENT(KUSER_EXCEPTION_STACK));
RtlZeroMemory(UserStack, sizeof(*UserStack));
/* Probe stack and copy exception record */
ProbeForWrite(UserExceptionRecord, Size, sizeof(ULONG64));
*UserExceptionRecord = *ExceptionRecord;
/* Copy Context and ExceptionFrame */
UserStack->Context = *Context;
UserStack->ExceptionRecord = *ExceptionRecord;
/* Setup the machine frame */
UserStack->MachineFrame.Rip = Context->Rip;
UserStack->MachineFrame.SegCs = Context->SegCs;
UserStack->MachineFrame.EFlags = Context->EFlags;
UserStack->MachineFrame.Rsp = Context->Rsp;
UserStack->MachineFrame.SegSs = Context->SegSs;
}
_SEH2_EXCEPT((LocalExceptRecord = *_SEH2_GetExceptionInformation()->ExceptionRecord),
EXCEPTION_EXECUTE_HANDLER)
@ -148,8 +148,8 @@ KiDispatchExceptionToUser(
_SEH2_END;
/* Now set the two params for the user-mode dispatcher */
TrapFrame->Rcx = (ULONG64)UserContext;
TrapFrame->Rdx = (ULONG64)UserExceptionRecord;
TrapFrame->Rcx = (ULONG64)&UserStack->ExceptionRecord;
TrapFrame->Rdx = (ULONG64)&UserStack->Context;
/* Set new Stack Pointer */
TrapFrame->Rsp = UserRsp;
@ -347,8 +347,9 @@ KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
/* Forward exception to user mode debugger */
if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return;
//KiDispatchExceptionToUser()
__debugbreak();
/* Forward exception to user mode (does not return) */
KiDispatchExceptionToUser(TrapFrame, &Context, ExceptionRecord);
NT_ASSERT(FALSE);
}
/* Try second chance */

View file

@ -998,6 +998,18 @@ typedef struct _UCALLOUT_FRAME
MACHINE_FRAME MachineFrame;
} UCALLOUT_FRAME, *PUCALLOUT_FRAME; // size = 0x0058
//
// Stack frame layout for KiUserExceptionDispatcher
// The name is totally made up
//
typedef struct _KUSER_EXCEPTION_STACK
{
CONTEXT Context;
EXCEPTION_RECORD ExceptionRecord;
ULONG64 Alignment;
MACHINE_FRAME MachineFrame;
} KUSER_EXCEPTION_STACK, * PKUSER_EXCEPTION_STACK;
typedef struct _DISPATCHER_CONTEXT
{
ULONG64 ControlPc;