Skip to content

Instantly share code, notes, and snippets.

@mgeeky
Forked from namazso/SuperReturn.c
Created June 21, 2025 07:37
Show Gist options
  • Save mgeeky/8c5ec8e6e91a009a6ad8a899d4e887b8 to your computer and use it in GitHub Desktop.
Save mgeeky/8c5ec8e6e91a009a6ad8a899d4e887b8 to your computer and use it in GitHub Desktop.

Revisions

  1. @namazso namazso revised this gist Jun 21, 2025. 1 changed file with 22 additions and 7 deletions.
    29 changes: 22 additions & 7 deletions SuperReturn.c
    Original file line number Diff line number Diff line change
    @@ -12,24 +12,35 @@ DECLSPEC_NOINLINE void SuperReturn(
    _In_opt_ ULONG_PTR RetVal,
    _In_opt_ PCONTEXT Context
    ) {

    CONTEXT LocalContext;
    if (!Context) {
    FramesToSkip += 1; // skip this frame
    LocalContext.ContextFlags = CONTEXT_INTEGER;
    LocalContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
    RtlCaptureContext(&LocalContext);
    Context = &LocalContext;
    }

    ULONG64 ControlPc = Context->Rip;
    #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
    Context->Rip = *(ULONG64*)Context->Rsp;
    Context->Rsp += sizeof(ULONG64);
    CTX_IP(Context) = *(ULONG64*)CTX_SP(Context);
    CTX_SP(Context) += sizeof(ULONG64);
    } else {
    PVOID HandlerData;
    ULONG64 EstablisherFrame;
    @@ -45,10 +56,14 @@ DECLSPEC_NOINLINE void SuperReturn(
    );
    }

    ControlPc = Context->Rip;
    ControlPc = CTX_IP(Context);
    }

    Context->Rax = RetVal;
    CTX_RV(Context) = RetVal;

    #undef CTX_IP
    #undef CTX_SP
    #undef CTX_RV

    NtContinue(Context, FALSE);
    }
    }
  2. @namazso namazso revised this gist Jun 21, 2025. 1 changed file with 7 additions and 7 deletions.
    14 changes: 7 additions & 7 deletions SuperReturn.c
    Original file line number Diff line number Diff line change
    @@ -9,8 +9,8 @@
    // @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 = 0,
    _In_opt_ PCONTEXT Context = nullptr
    _In_opt_ ULONG_PTR RetVal,
    _In_opt_ PCONTEXT Context
    ) {
    CONTEXT LocalContext;
    if (!Context) {
    @@ -20,11 +20,11 @@ DECLSPEC_NOINLINE void SuperReturn(
    Context = &LocalContext;
    }

    auto ControlPc = Context->Rip;
    ULONG64 ControlPc = Context->Rip;

    for (ULONG i = 0; i < FramesToSkip; i++) {
    ULONG_PTR ImageBase{};
    const auto FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, nullptr);
    ULONG_PTR ImageBase = 0;
    PRUNTIME_FUNCTION FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);

    if (!FunctionEntry) {
    // leaf
    @@ -41,7 +41,7 @@ DECLSPEC_NOINLINE void SuperReturn(
    Context,
    &HandlerData,
    &EstablisherFrame,
    nullptr
    NULL
    );
    }

    @@ -51,4 +51,4 @@ DECLSPEC_NOINLINE void SuperReturn(
    Context->Rax = RetVal;

    NtContinue(Context, FALSE);
    }
    }
  3. @namazso namazso created this gist Jun 21, 2025.
    54 changes: 54 additions & 0 deletions SuperReturn.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,54 @@
    // 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 = 0,
    _In_opt_ PCONTEXT Context = nullptr
    ) {
    CONTEXT LocalContext;
    if (!Context) {
    FramesToSkip += 1; // skip this frame
    LocalContext.ContextFlags = CONTEXT_INTEGER;
    RtlCaptureContext(&LocalContext);
    Context = &LocalContext;
    }

    auto ControlPc = Context->Rip;

    for (ULONG i = 0; i < FramesToSkip; i++) {
    ULONG_PTR ImageBase{};
    const auto FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, nullptr);

    if (!FunctionEntry) {
    // leaf
    Context->Rip = *(ULONG64*)Context->Rsp;
    Context->Rsp += sizeof(ULONG64);
    } else {
    PVOID HandlerData;
    ULONG64 EstablisherFrame;
    RtlVirtualUnwind(
    UNW_FLAG_NHANDLER,
    ImageBase,
    ControlPc,
    FunctionEntry,
    Context,
    &HandlerData,
    &EstablisherFrame,
    nullptr
    );
    }

    ControlPc = Context->Rip;
    }

    Context->Rax = RetVal;

    NtContinue(Context, FALSE);
    }