[RTL/x64] Implement RtlRaiseException in asm

This fixes invalid contexts being passed to RtlDispatchException. Also update the ExceptionAddress field in the EXCEPTION_FRAME, to match the Rip value in the CONTEXT, which is required for proper unwinding.
This commit is contained in:
Timo Kreuzer 2018-03-02 08:48:34 +02:00
parent ba170757d6
commit 83e741c643
2 changed files with 75 additions and 44 deletions

View file

@ -13,50 +13,6 @@
/* PUBLIC FUNCTIONS **********************************************************/
VOID
NTAPI
RtlRaiseException(IN PEXCEPTION_RECORD ExceptionRecord)
{
CONTEXT Context;
NTSTATUS Status = STATUS_INVALID_DISPOSITION;
/* Capture the current context */
RtlCaptureContext(&Context);
/* Fix up Context.Rip for the caller */
Context.Rip = (ULONG64)_ReturnAddress();
/* Fix up Context.Rsp for the caller */
Context.Rsp = (ULONG64)_AddressOfReturnAddress() + 8;
/* Save the exception address */
ExceptionRecord->ExceptionAddress = (PVOID)Context.Rip;
/* Check if user mode debugger is active */
if (RtlpCheckForActiveDebugger())
{
/* Raise an exception immediately */
Status = ZwRaiseException(ExceptionRecord, &Context, TRUE);
}
else
{
/* Dispatch the exception and check if we should continue */
if (!RtlDispatchException(ExceptionRecord, &Context))
{
/* Raise the exception */
Status = ZwRaiseException(ExceptionRecord, &Context, FALSE);
}
else
{
/* Continue, go back to previous context */
Status = ZwContinue(&Context, FALSE);
}
}
/* If we returned, raise a status */
RtlRaiseStatus(Status);
}
/*
* @unimplemented
*/

View file

@ -233,6 +233,81 @@ ReturnFar:
.ENDP
EXTERN RtlpCheckForActiveDebugger:PROC
EXTERN RtlDispatchException:PROC
EXTERN ZwContinue:PROC
EXTERN ZwRaiseException:PROC
EXTERN RtlRaiseStatus:PROC
/*
* VOID
* RtlRaiseException (
* _In_ PEXCEPTION_RECORD ExceptionRecord);
*/
PUBLIC RtlRaiseException
.PROC RtlRaiseException
/* Allocate stack space for a CONTEXT record */
sub rsp, CONTEXT_FRAME_LENGTH + 8
.allocstack CONTEXT_FRAME_LENGTH + 8
/* Save the ExceptionRecord pointer */
mov [rsp + CONTEXT_FRAME_LENGTH + 8 + P1Home], rcx
.endprolog
/* Save the return address in EXCEPTION_RECORD.ExceptionAddress */
mov rdx, [rsp + CONTEXT_FRAME_LENGTH + 8]
mov [rcx + ErExceptionAddress], rdx
/* Capture the current context */
mov rcx, rsp
call RtlCaptureContext
/* Fix up CONTEXT.Rip for the caller (RtlCaptureContext doesn't change rdx!) */
mov [rsp + CxRip], rdx
/* Fix up CONTEXT.Rsp for the caller (+8 for the return address) */
lea rdx, [rsp + CONTEXT_FRAME_LENGTH + 8 + 8]
mov [rsp + CxRsp], rdx
/* Check if a user mode debugger is active */
call RtlpCheckForActiveDebugger
test al, al
mov r8b, 1
jnz RaiseException
/* Dispatch the exception */
mov rcx, [rsp + CONTEXT_FRAME_LENGTH + 8 + P1Home]
mov rdx, rsp
call RtlDispatchException
/* Check if it was handled */
test al, al
mov r8b, 0
jz RaiseException
/* It was handled, continue with the updated context */
mov rcx, rsp
mov dl, 0
call ZwContinue
jmp RaiseStatus
RaiseException:
mov rcx, [rsp + CxP1Home]
mov rdx, rsp
call ZwRaiseException
RaiseStatus:
mov rcx, rax
mov rdx, rsp
call RtlRaiseStatus
.ENDP
END