[NTOS:KE/x64] Fix unwinding in KiUserApcDispatcher

This adds a MACHINE_FRAME to the user mode APC dispatcher stack frame.
This commit is contained in:
Timo Kreuzer 2024-12-11 16:47:28 +02:00
parent 91948dea80
commit 29721ac552
3 changed files with 47 additions and 6 deletions

View file

@ -33,6 +33,32 @@ PUBLIC LdrInitializeThunk
PUBLIC KiUserApcDispatcher
.PROC KiUserApcDispatcher
/* The stack is set up with a UAPC_FRAME, which ends with a MACHINE_FRAME */
.PUSHFRAME
.ALLOCSTACK CONTEXT_FRAME_LENGTH
/* The stack points to a CONTEXT structure.
Create unwind ops for all nonvolatile registers */
.SAVEREG rbx, CxRbx
.SAVEREG rbp, CxRbp
.SAVEREG rsi, CxRsi
.SAVEREG rdi, CxRdi
.SAVEREG r12, CxR12
.SAVEREG r13, CxR13
.SAVEREG r14, CxR14
.SAVEREG r15, CxR15
.SAVEXMM128 xmm6, CxXmm6
.SAVEXMM128 xmm7, CxXmm7
.SAVEXMM128 xmm8, CxXmm8
.SAVEXMM128 xmm9, CxXmm9
.SAVEXMM128 xmm10, CxXmm10
.SAVEXMM128 xmm11, CxXmm11
.SAVEXMM128 xmm12, CxXmm12
.SAVEXMM128 xmm13, CxXmm13
.SAVEXMM128 xmm14, CxXmm14
.SAVEXMM128 xmm15, CxXmm15
.endprolog
/* We enter with a 16 byte aligned stack */

View file

@ -16,8 +16,8 @@
*
* \brief
* Prepares the current trap frame (which must have come from user mode)
* with the ntdll.KiUserApcDispatcher entrypoint, copying a CONTEXT
* record with the context from the old trap frame to the threads user
* with the ntdll.KiUserApcDispatcher entrypoint, copying a UAPC_FRAME
* structure with the context from the old trap frame to the threads user
* mode stack.
*
* \param ExceptionFrame - Pointer to the Exception Frame
@ -53,20 +53,22 @@ KiInitializeUserApc(
_In_ PVOID SystemArgument1,
_In_ PVOID SystemArgument2)
{
PUAPC_FRAME ApcFrame;
PCONTEXT Context;
EXCEPTION_RECORD ExceptionRecord;
/* Sanity check, that the trap frame is from user mode */
ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode);
/* Align the user tack to 16 bytes and allocate space for a CONTEXT structure */
Context = (PCONTEXT)ALIGN_DOWN_POINTER_BY(TrapFrame->Rsp, 16) - 1;
/* Allocate a 16 byte aligned UAPC_FRAME structure on the user stack */
ApcFrame = (PUAPC_FRAME)ALIGN_DOWN_POINTER_BY(TrapFrame->Rsp - sizeof(*ApcFrame), 16);
Context = &ApcFrame->Context;
/* Protect with SEH */
_SEH2_TRY
{
/* Probe the context */
ProbeForWrite(Context, sizeof(CONTEXT), 16);
/* Probe the user mode APC frame */
ProbeForWrite(ApcFrame, sizeof(*ApcFrame), 16);
/* Convert the current trap frame to a context */
Context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
@ -77,6 +79,10 @@ KiInitializeUserApc(
Context->P2Home = (ULONG64)SystemArgument1;
Context->P3Home = (ULONG64)SystemArgument2;
Context->P4Home = (ULONG64)NormalRoutine;
/* Set up the machine frame for unwinding */
ApcFrame->MachineFrame.Rip = TrapFrame->Rip;
ApcFrame->MachineFrame.Rsp = TrapFrame->Rsp;
}
_SEH2_EXCEPT(ExceptionRecord = *_SEH2_GetExceptionInformation()->ExceptionRecord, EXCEPTION_EXECUTE_HANDLER)
{

View file

@ -1073,6 +1073,15 @@ typedef struct _UCALLOUT_FRAME
MACHINE_FRAME MachineFrame;
} UCALLOUT_FRAME, *PUCALLOUT_FRAME; // size = 0x0058
//
// User side APC dispatcher frame
//
typedef struct _UAPC_FRAME
{
CONTEXT Context;
MACHINE_FRAME MachineFrame;
} UAPC_FRAME, *PUAPC_FRAME;
//
// Stack frame layout for KiUserExceptionDispatcher
// The name is totally made up