-
-
Save mgeeky/8c5ec8e6e91a009a6ad8a899d4e887b8 to your computer and use it in GitHub Desktop.
SuperReturn
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Return, but across multiple frames. | |
// | |
// This function unwinds the given number of frames, then sets the return value provided, emulating as if this number | |
// of functions returned, with the last one returning the value provided in RetVal. Can be used to hook a callee when | |
// you don't have a convenient way to hook it directly and actually just want to stub it out with a return value. | |
// | |
// @param FramesToSkip The number of frames to skip, starting from the current frame. | |
// @param RetVal The value to return from the last frame. | |
// @param Context Context to start from, in case you want to SuperReturn from somewhere deeper. | |
DECLSPEC_NOINLINE void SuperReturn( | |
_In_ ULONG FramesToSkip, | |
_In_opt_ ULONG_PTR RetVal, | |
_In_opt_ PCONTEXT Context | |
) { | |
CONTEXT LocalContext; | |
if (!Context) { | |
FramesToSkip += 1; // skip this frame | |
LocalContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; | |
RtlCaptureContext(&LocalContext); | |
Context = &LocalContext; | |
} | |
#if defined(_M_X64) | |
#define CTX_IP(Ctx) (Ctx->Rip) | |
#define CTX_SP(Ctx) (Ctx->Rsp) | |
#define CTX_RV(Ctx) (Ctx->Rax) | |
#elif defined(_M_ARM64) | |
#define CTX_IP(Ctx) (Ctx->Pc) | |
#define CTX_SP(Ctx) (Ctx->Sp) | |
#define CTX_RV(Ctx) (Ctx->X0) | |
#endif | |
ULONG64 ControlPc = CTX_IP(Context); | |
for (ULONG i = 0; i < FramesToSkip; i++) { | |
ULONG_PTR ImageBase = 0; | |
PRUNTIME_FUNCTION FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL); | |
if (!FunctionEntry) { | |
// leaf | |
CTX_IP(Context) = *(ULONG64*)CTX_SP(Context); | |
CTX_SP(Context) += sizeof(ULONG64); | |
} else { | |
PVOID HandlerData; | |
ULONG64 EstablisherFrame; | |
RtlVirtualUnwind( | |
UNW_FLAG_NHANDLER, | |
ImageBase, | |
ControlPc, | |
FunctionEntry, | |
Context, | |
&HandlerData, | |
&EstablisherFrame, | |
NULL | |
); | |
} | |
ControlPc = CTX_IP(Context); | |
} | |
CTX_RV(Context) = RetVal; | |
#undef CTX_IP | |
#undef CTX_SP | |
#undef CTX_RV | |
NtContinue(Context, FALSE); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment