[RTL] Fix RtlVirtualUnwind

This commit is contained in:
Timo Kreuzer 2022-08-19 13:03:22 +02:00
parent 90d2e12dfa
commit aade1ab01b

View file

@ -303,6 +303,7 @@ __inline
BOOLEAN
RtlpTryToUnwindEpilog(
_Inout_ PCONTEXT Context,
_In_ ULONG64 ControlPc,
_Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
_In_ ULONG64 ImageBase,
_In_ PRUNTIME_FUNCTION FunctionEntry)
@ -316,7 +317,7 @@ RtlpTryToUnwindEpilog(
/* Make a local copy of the context */
LocalContext = *Context;
InstrPtr = (BYTE*)LocalContext.Rip;
InstrPtr = (BYTE*)ControlPc;
/* Check if first instruction of epilog is "add rsp, x" */
Instr = *(DWORD*)InstrPtr;
@ -339,7 +340,10 @@ RtlpTryToUnwindEpilog(
else if ( (Instr & 0x38fffe) == 0x208d48 )
{
/* Get the register */
Reg = ((Instr << 8) | (Instr >> 16)) & 0x7;
Reg = (Instr >> 16) & 0x7;
/* REX.R */
Reg += (Instr & 1) * 8;
LocalContext.Rsp = GetReg(&LocalContext, Reg);
@ -353,13 +357,13 @@ RtlpTryToUnwindEpilog(
else if (Mod == 1)
{
/* 1 byte displacement */
LocalContext.Rsp += Instr >> 24;
LocalContext.Rsp += (LONG)(CHAR)(Instr >> 24);
InstrPtr += 4;
}
else if (Mod == 2)
{
/* 4 bytes displacement */
LocalContext.Rsp += *(DWORD*)(InstrPtr + 3);
LocalContext.Rsp += *(LONG*)(InstrPtr + 3);
InstrPtr += 7;
}
}
@ -453,11 +457,17 @@ GetEstablisherFrame(
i < UnwindInfo->CountOfCodes;
i += UnwindOpSlots(UnwindInfo->UnwindCode[i]))
{
/* Skip codes past our code offset */
if (UnwindInfo->UnwindCode[i].CodeOffset > CodeOffset)
{
continue;
}
/* Check for SET_FPREG */
if (UnwindInfo->UnwindCode[i].UnwindOp == UWOP_SET_FPREG)
{
return GetReg(Context, UnwindInfo->FrameRegister) -
UnwindInfo->FrameOffset * 16;
UnwindInfo->FrameOffset * 16;
}
}
@ -477,18 +487,18 @@ RtlVirtualUnwind(
_Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers)
{
PUNWIND_INFO UnwindInfo;
ULONG_PTR CodeOffset;
ULONG_PTR ControlRva, CodeOffset;
ULONG i, Offset;
UNWIND_CODE UnwindCode;
BYTE Reg;
PULONG LanguageHandler;
/* Use relative virtual address */
ControlPc -= ImageBase;
/* Get relative virtual address */
ControlRva = ControlPc - ImageBase;
/* Sanity checks */
if ( (ControlPc < FunctionEntry->BeginAddress) ||
(ControlPc >= FunctionEntry->EndAddress) )
if ( (ControlRva < FunctionEntry->BeginAddress) ||
(ControlRva >= FunctionEntry->EndAddress) )
{
return NULL;
}
@ -498,17 +508,16 @@ RtlVirtualUnwind(
/* The language specific handler data follows the unwind info */
LanguageHandler = ALIGN_UP_POINTER_BY(&UnwindInfo->UnwindCode[UnwindInfo->CountOfCodes], sizeof(ULONG));
*HandlerData = (LanguageHandler + 1);
/* Calculate relative offset to function start */
CodeOffset = ControlPc - FunctionEntry->BeginAddress;
CodeOffset = ControlRva - FunctionEntry->BeginAddress;
*EstablisherFrame = GetEstablisherFrame(Context, UnwindInfo, CodeOffset);
/* Check if we are in the function epilog and try to finish it */
if (CodeOffset > UnwindInfo->SizeOfProlog)
if ((CodeOffset > UnwindInfo->SizeOfProlog) && (UnwindInfo->CountOfCodes > 0))
{
if (RtlpTryToUnwindEpilog(Context, ContextPointers, ImageBase, FunctionEntry))
if (RtlpTryToUnwindEpilog(Context, ControlPc, ContextPointers, ImageBase, FunctionEntry))
{
/* There's no exception routine */
return NULL;
@ -565,7 +574,7 @@ RepeatChainedInfo:
case UWOP_SAVE_NONVOL:
Reg = UnwindCode.OpInfo;
Offset = *(USHORT*)(&UnwindInfo->UnwindCode[i + 1]);
Offset = UnwindInfo->UnwindCode[i + 1].FrameOffset;
SetRegFromStackValue(Context, ContextPointers, Reg, (DWORD64*)Context->Rsp + Offset);
i += 2;
break;
@ -588,15 +597,15 @@ RepeatChainedInfo:
case UWOP_SAVE_XMM128:
Reg = UnwindCode.OpInfo;
Offset = *(USHORT*)(&UnwindInfo->UnwindCode[i + 1]);
SetXmmRegFromStackValue(Context, ContextPointers, Reg, (M128A*)(Context->Rsp + Offset));
Offset = UnwindInfo->UnwindCode[i + 1].FrameOffset;
SetXmmRegFromStackValue(Context, ContextPointers, Reg, (M128A*)Context->Rsp + Offset);
i += 2;
break;
case UWOP_SAVE_XMM128_FAR:
Reg = UnwindCode.OpInfo;
Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i + 1]);
SetXmmRegFromStackValue(Context, ContextPointers, Reg, (M128A*)(Context->Rsp + Offset));
SetXmmRegFromStackValue(Context, ContextPointers, Reg, (M128A*)Context->Rsp + Offset);
i += 3;
break;
@ -604,11 +613,8 @@ RepeatChainedInfo:
/* OpInfo is 1, when an error code was pushed, otherwise 0. */
Context->Rsp += UnwindCode.OpInfo * sizeof(DWORD64);
/* Now pop the MACHINE_FRAME (Yes, "magic numbers", deal with it) */
/* Now pop the MACHINE_FRAME (RIP/RSP only. And yes, "magic numbers", deal with it) */
Context->Rip = *(PDWORD64)(Context->Rsp + 0x00);
Context->SegCs = *(PDWORD64)(Context->Rsp + 0x08);
Context->EFlags = *(PDWORD64)(Context->Rsp + 0x10);
Context->SegSs = *(PDWORD64)(Context->Rsp + 0x20);
Context->Rsp = *(PDWORD64)(Context->Rsp + 0x18);
ASSERT((i + 1) == UnwindInfo->CountOfCodes);
goto Exit;
@ -635,8 +641,9 @@ RepeatChainedInfo:
Exit:
/* Check if we have a handler and return it */
if (UnwindInfo->Flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
if (UnwindInfo->Flags & (HandlerType & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER)))
{
*HandlerData = (LanguageHandler + 1);
return RVA(ImageBase, *LanguageHandler);
}