X64 VC 堆栈检查失败处理代码分析

基本代码:

/***
*gs_report.c - Report a /GS security check failure
***/

#include <windows.h>
#include <dbgint.h>     /* needed for _CRT_DEBUGGER_HOOK */
#include <awint.h>      /* needed for Win32 API helpers */

extern UINT_PTR __security_cookie;
extern UINT_PTR __security_cookie_complement;

static EXCEPTION_RECORD         GS_ExceptionRecord;
static CONTEXT                  GS_ContextRecord;
static const EXCEPTION_POINTERS GS_ExceptionPointers = {
    &GS_ExceptionRecord,
    &GS_ContextRecord
};

void capture_current_context(CONTEXT* context) {
    ULONG64 ControlPc;
    ULONG64 EstablisherFrame;
    ULONG64 ImageBase;
    PRUNTIME_FUNCTION FunctionEntry;
    PVOID HandlerData;
    RtlCaptureContext(context);

    ControlPc = context->Rip;
    ImageBase = context->SegFs;
    // Get the function entry for the current instruction pointer
    FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
    if (FunctionEntry) {
        KNONVOLATILE_CONTEXT_POINTERS nvContext = {0};
        PRUNTIME_FUNCTION unwindInfo = RtlVirtualUnwind(UNW_FLAG_NHANDLER, 
                                                       ImageBase, 
                                                       ControlPc, 
                                                       FunctionEntry, 
                                                       &context, 
                                                       &EstablisherFrame,
                                                       NULL);
        if (unwindInfo) {
            std::cout << "Unwind Successful" << std::endl;
        } else {
            std::cout << "Unwind Failed" << std::endl;
        }
    }
}

void capture_previous_context(CONTEXT* context) {
    ULONG64 ControlPc;
    ULONG64 EstablisherFrame;
    ULONG64 ImageBase;
    PRUNTIME_FUNCTION FunctionEntry;
    PVOID HandlerData;
    RtlCaptureContext(context);

    ControlPc = context->Rip;
    ImageBase = context->SegFs;

    for (frames = 0; frames < 2; frames++)
    {
        // Get the function entry for the current instruction pointer
        FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
        if (FunctionEntry) {
            KNONVOLATILE_CONTEXT_POINTERS nvContext = {0};
            PRUNTIME_FUNCTION unwindInfo = RtlVirtualUnwind(UNW_FLAG_NHANDLER, 
                                                        ImageBase, 
                                                        ControlPc, 
                                                        FunctionEntry, 
                                                        &context, 
                                                        &EstablisherFrame,
                                                        NULL);
            if (unwindInfo) {
                std::cout << "Unwind Successful" << std::endl;
            } else {
                std::cout << "Unwind Failed" << std::endl;
            }
        }
    }
}


static BOOL DebuggerWasPresent;

#define STATUS_SECURITY_CHECK_FAILURE STATUS_STACK_BUFFER_OVERRUN

__declspec(noreturn) void __cdecl __raise_securityfailure(
    PEXCEPTION_POINTERS ExceptionPointers
    )
{
    DebuggerWasPresent = IsDebuggerPresent();
    _CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE);

    __crtUnhandledException(ExceptionPointers);

    if (!DebuggerWasPresent)
    {
        _CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE);
    }

    __crtTerminateProcess(STATUS_SECURITY_CHECK_FAILURE);
}

__declspec(noreturn) void __cdecl __report_gsfailure(ULONGLONG StackCookie)
{
   if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
        __fastfail(FAST_FAIL_STACK_COOKIE_CHECK_FAILURE);

    __crtCapturePreviousContext(&GS_ContextRecord); /* Capture the preceding frame context */

    GS_ContextRecord.Rip = (ULONGLONG) _ReturnAddress();
    GS_ContextRecord.Rsp = (ULONGLONG) _AddressOfReturnAddress()+8;
    GS_ExceptionRecord.ExceptionAddress = (PVOID)GS_ContextRecord.Rip;
    GS_ContextRecord.Rcx = StackCookie;

    GS_ExceptionRecord.ExceptionCode  = STATUS_SECURITY_CHECK_FAILURE;
    GS_ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
    GS_ExceptionRecord.NumberParameters = 1;
    GS_ExceptionRecord.ExceptionInformation[0] = FAST_FAIL_STACK_COOKIE_CHECK_FAILURE;

    cookie[0] = __security_cookie;
    cookie[1] = __security_cookie_complement;

    __raise_securityfailure((EXCEPTION_POINTERS *)&GS_ExceptionPointers);
}

__declspec(noreturn) void __cdecl __report_securityfailureEx(
    _In_ ULONG FailureCode,
    _In_ ULONG NumberParameters,
    _In_reads_opt_(NumberParameters) void **Parameters
    )
{
    ULONG i;

    if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
        __fastfail(FailureCode);

    __crtCaptureCurrentContext(&GS_ContextRecord);
    GS_ContextRecord.Rip = (ULONGLONG) _ReturnAddress();
    GS_ContextRecord.Rsp = (ULONGLONG) _AddressOfReturnAddress()+8;
    GS_ExceptionRecord.ExceptionAddress = (PVOID)GS_ContextRecord.Rip;

    GS_ExceptionRecord.ExceptionCode  = STATUS_SECURITY_CHECK_FAILURE;
    GS_ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;

    if (NumberParameters > 0 && Parameters == NULL) {
        NumberParameters = 0;
    }

    if (NumberParameters > EXCEPTION_MAXIMUM_PARAMETERS - 1) {
        NumberParameters--;
    }

    GS_ExceptionRecord.NumberParameters = NumberParameters + 1;
    GS_ExceptionRecord.ExceptionInformation[0] = FailureCode;

    for (i = 0; i < NumberParameters; i++) {
        GS_ExceptionRecord.ExceptionInformation[i + 1] = (ULONG_PTR)Parameters[i];
    }
    __raise_securityfailure((EXCEPTION_POINTERS *)&GS_ExceptionPointers);
}

__declspec(noreturn) void __cdecl __report_securityfailure(ULONG FailureCode)
{
    if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
        __fastfail(FailureCode);

    __crtCaptureCurrentContext(&GS_ContextRecord);
    GS_ContextRecord.Rip = (ULONGLONG) _ReturnAddress();
    GS_ContextRecord.Rsp = (ULONGLONG) _AddressOfReturnAddress()+8;
    GS_ExceptionRecord.ExceptionAddress = (PVOID)GS_ContextRecord.Rip;

    GS_ExceptionRecord.ExceptionCode  = STATUS_SECURITY_CHECK_FAILURE;
    GS_ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;

    GS_ExceptionRecord.NumberParameters = 1;
    GS_ExceptionRecord.ExceptionInformation[0] = FailureCode;

    __raise_securityfailure((EXCEPTION_POINTERS *)&GS_ExceptionPointers);
}

__declspec(noreturn) void __cdecl __report_rangecheckfailure(void)
{
    __report_securityfailure(FAST_FAIL_RANGE_CHECK_FAILURE);
}

这段代码主要用于处理 /GS 安全检查失败的情况,/GS 是 Microsoft Visual C++ 编译器的一个安全编译选项,用于检测堆栈缓冲区溢出。

代码注释和分析

头文件和外部变量定义
#include <windows.h>       /* Windows API 头文件 */
#include <dbgint.h>        /* 需要用于 _CRT_DEBUGGER_HOOK 宏 */
#include <awint.h>         /* 需要用于 Win32 API 辅助函数 */

extern UINT_PTR __security_cookie;             /* 堆栈保护 cookie */
extern UINT_PTR __security_cookie_complement;  /* 堆栈保护 cookie 的补码 */

全局变量
static EXCEPTION_RECORD         GS_ExceptionRecord;         /* 用于存储异常记录 */
static CONTEXT                  GS_ContextRecord;           /* 用于存储当前线程的上下文信息 */
static const EXCEPTION_POINTERS GS_ExceptionPointers = {    /* 用于存储异常指针 */
    &GS_ExceptionRecord,
    &GS_ContextRecord
};

捕获当前上下文信息
void capture_current_context(CONTEXT* context) {
    ULONG64 ControlPc;                    /* 当前指令指针 */
    ULONG64 EstablisherFrame;              /* 建立者帧地址 */
    ULONG64 ImageBase;                     /* 映像基址 */
    PRUNTIME_FUNCTION FunctionEntry;       /* 运行时函数入口 */
    PVOID HandlerData;                      /* 处理数据指针 */

    RtlCaptureContext(context);            /* 捕获当前线程的上下文信息 */

    ControlPc = context->Rip;              /* 获取当前指令指针 */
    ImageBase = context->SegFs;            /* 获取当前映像基址 */

    // 获取当前指令指针对应的函数入口
    FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
    if (FunctionEntry) {
        KNONVOLATILE_CONTEXT_POINTERS nvContext = {0};  /* 初始化非易失性上下文指针 */
        PRUNTIME_FUNCTION unwindInfo = RtlVirtualUnwind(UNW_FLAG_NHANDLER, 
                                                       ImageBase, 
                                                       ControlPc, 
                                                       FunctionEntry, 
                                                       &context, 
                                                       &EstablisherFrame,
                                                       NULL);  /* 展开调用栈 */

        if (unwindInfo) {
            std::cout << "Unwind Successful" << std::endl;  /* 展开成功 */
        } else {
            std::cout << "Unwind Failed" << std::endl;      /* 展开失败 */
        }
    }
}

捕获前一个上下文信息
void capture_previous_context(CONTEXT* context) {
    ULONG64 ControlPc;                    /* 当前指令指针 */
    ULONG64 EstablisherFrame;              /* 建立者帧地址 */
    ULONG64 ImageBase;                     /* 映像基址 */
    PRUNTIME_FUNCTION FunctionEntry;       /* 运行时函数入口 */
    PVOID HandlerData;                      /* 处理数据指针 */

    RtlCaptureContext(context);            /* 捕获当前线程的上下文信息 */

    ControlPc = context->Rip;              /* 获取当前指令指针 */
    ImageBase = context->SegFs;             /* 获取当前映像基址 */

    for (int frames = 0; frames < 2; frames++) {
        // 获取当前指令指针对应的函数入口
        FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
        if (FunctionEntry) {
            KNONVOLATILE_CONTEXT_POINTERS nvContext = {0};  /* 初始化非易失性上下文指针 */
            PRUNTIME_FUNCTION unwindInfo = RtlVirtualUnwind(UNW_FLAG_NHANDLER, 
                                                           ImageBase, 
                                                           ControlPc, 
                                                           FunctionEntry, 
                                                           &context, 
                                                           &EstablisherFrame,
                                                           NULL);  /* 展开调用栈 */

            if (unwindInfo) {
                std::cout << "Unwind Successful" << std::endl;  /* 展开成功 */
            } else {
                std::cout << "Unwind Failed" << std::endl;      /* 展开失败 */
            }

            ControlPc = (ULONG64)EstablisherFrame;  /* 更新指令指针为建立者帧地址 */
        } else {
            break;  /* 如果找不到函数入口,退出循环 */
        }
    }
}

处理安全检查失败
static BOOL DebuggerWasPresent;  /* 用于记录调试器是否存在 */

#define STATUS_SECURITY_CHECK_FAILURE STATUS_STACK_BUFFER_OVERRUN  /* 定义安全检查失败的状态码 */

__declspec(noreturn) void __cdecl __raise_securityfailure(
    PEXCEPTION_POINTERS ExceptionPointers
    )
{
    DebuggerWasPresent = IsDebuggerPresent();  /* 检查调试器是否存在 */
    _CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE);  /* 触发调试器钩子 */

    __crtUnhandledException(ExceptionPointers);  /* 处理未处理的异常 */

    if (!DebuggerWasPresent) {
        _CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE);  /* 重新触发调试器钩子 */
    }

    __crtTerminateProcess(STATUS_SECURITY_CHECK_FAILURE);  /* 终止进程 */
}

报告堆栈保护 cookie 检查失败
__declspec(noreturn) void __cdecl __report_gsfailure(ULONGLONG StackCookie)
{
    if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))  /* 检查处理器是否支持快速失败 */
        __fastfail(FAST_FAIL_STACK_COOKIE_CHECK_FAILURE);  /* 快速失败 */

    __crtCapturePreviousContext(&GS_ContextRecord);  /* 捕获前一个上下文信息 */

    GS_ContextRecord.Rip = (ULONGLONG) _ReturnAddress();  /* 设置当前指令指针为返回地址 */
    GS_ContextRecord.Rsp = (ULONGLONG) _AddressOfReturnAddress() + 8;  /* 设置栈指针 */
    GS_ExceptionRecord.ExceptionAddress = (PVOID)GS_ContextRecord.Rip;  /* 设置异常地址 */

    GS_ContextRecord.Rcx = StackCookie;  /* 设置 Rcx 寄存器为堆栈保护 cookie */

    GS_ExceptionRecord.ExceptionCode  = STATUS_SECURITY_CHECK_FAILURE;  /* 设置异常代码 */
    GS_ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;  /* 设置异常标志 */
    GS_ExceptionRecord.NumberParameters = 1;  /* 设置参数数量 */
    GS_ExceptionRecord.ExceptionInformation[0] = FAST_FAIL_STACK_COOKIE_CHECK_FAILURE;  /* 设置参数 */

    __raise_securityfailure((EXCEPTION_POINTERS *)&GS_ExceptionPointers);  /* 触发安全检查失败处理 */
}

报告安全检查失败(扩展版本)
__declspec(noreturn) void __cdecl __report_securityfailureEx(
    _In_ ULONG FailureCode,
    _In_ ULONG NumberParameters,
    _In_reads_opt_(NumberParameters) void **Parameters
    )
{
    ULONG i;

    if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))  /* 检查处理器是否支持快速失败 */
        __fastfail(FailureCode);  /* 快速失败 */

    __crtCaptureCurrentContext(&GS_ContextRecord);  /* 捕获当前上下文信息 */
    GS_ContextRecord.Rip = (ULONGLONG) _ReturnAddress();  /* 设置当前指令指针为返回地址 */
    GS_ContextRecord.Rsp = (ULONGLONG) _AddressOfReturnAddress() + 8;  /* 设置栈指针 */
    GS_ExceptionRecord.ExceptionAddress = (PVOID)GS_ContextRecord.Rip;  /* 设置异常地址 */

    GS_ExceptionRecord.ExceptionCode  = STATUS_SECURITY_CHECK_FAILURE;  /* 设置异常代码 */
    GS_ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;  /* 设置异常标志 */

    if (NumberParameters > 0 && Parameters == NULL) {  /* 检查参数是否为空 */
        NumberParameters = 0;
    }

    if (NumberParameters > EXCEPTION_MAXIMUM_PARAMETERS - 1) {  /* 检查参数数量是否超出最大值 */
        NumberParameters--;
    }

    GS_ExceptionRecord.NumberParameters = NumberParameters + 1;  /* 设置参数数量 */
    GS_ExceptionRecord.ExceptionInformation[0] = FailureCode;  /* 设置参数 */

    for (i = 0; i < NumberParameters; i++) {  /* 设置其他参数 */
        GS_ExceptionRecord.ExceptionInformation[i + 1] = (ULONG_PTR)Parameters[i];
    }

    __raise_securityfailure((EXCEPTION_POINTERS *)&GS_ExceptionPointers);  /* 触发安全检查失败处理 */
}

报告特定的安全检查失败
__declspec(noreturn) void __cdecl __report_securityfailure(ULONG FailureCode)
{
    if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))  /* 检查处理器是否支持快速失败 */
        __fastfail(FailureCode);  /* 快速失败 */

    __crtCaptureCurrentContext(&GS_ContextRecord);  /* 捕获当前上下文信息 */
    GS_ContextRecord.Rip = (ULONGLONG) _ReturnAddress();  /* 设置当前指令指针为返回地址 */
    GS_ContextRecord.Rsp = (ULONGLONG) _AddressOfReturnAddress() + 8;  /* 设置栈指针 */
    GS_ExceptionRecord.ExceptionAddress = (PVOID)GS_ContextRecord.Rip;  /* 设置异常地址 */

    GS_ExceptionRecord.ExceptionCode  = STATUS_SECURITY_CHECK_FAILURE;  /* 设置异常代码 */
    GS_ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;  /* 设置异常标志 */

    GS_ExceptionRecord.NumberParameters = 1;  /* 设置参数数量 */
    GS_ExceptionRecord.ExceptionInformation[0] = FailureCode;  /* 设置参数 */

    __raise_securityfailure((EXCEPTION_POINTERS *)&GS_ExceptionPointers);  /* 触发安全检查失败处理 */
}

报告范围检查失败
__declspec(noreturn) void __cdecl __report_rangecheckfailure(void)
{
    __report_securityfailure(FAST_FAIL_RANGE_CHECK_FAILURE);  /* 报告范围检查失败 */
}

代码分析

  1. capture_current_context 函数

    • 功能:捕获当前线程的上下文信息,并尝试查找当前指令指针对应的函数入口点,然后展开调用栈。
    • 使用:用于调试和异常处理,获取当前函数的上下文信息。
  2. capture_previous_context 函数

    • 功能:捕获前一个调用栈帧的上下文信息,并尝试展开调用栈。
    • 使用:用于获取前一个函数的上下文信息,以便更好地理解调用栈。
  3. __raise_securityfailure 函数

    • 功能:处理 /GS 安全检查失败,触发调试器钩子,记录调试器是否存在,调用未处理异常处理函数,最后终止进程。
    • 使用:在检测到 /GS 安全检查失败时调用,确保进程安全终止并提供调试信息。
  4. __report_gsfailure 函数

    • 功能:报告堆栈保护 cookie 检查失败,设置异常记录和上下文记录,然后调用 __raise_securityfailure 函数处理异常。
    • 使用:当检测到堆栈保护 cookie 被篡改时调用,确保安全检查失败能够被正确处理。
  5. __report_securityfailureEx 函数

    • 功能:报告特定的安全检查失败,支持多个参数,设置异常记录和上下文记录,然后调用 __raise_securityfailure 函数处理异常。
    • 使用:当需要报告带有额外参数的安全检查失败时调用,提供更多调试信息。
  6. __report_securityfailure 函数

    • 功能:报告特定的安全检查失败,设置异常记录和上下文记录,然后调用 __raise_securityfailure 函数处理异常。
    • 使用:当检测到特定的安全检查失败时调用,确保安全检查失败能够被正确处理。
  7. __report_rangecheckfailure 函数

    • 功能:报告范围检查失败,调用 __report_securityfailure 函数处理异常。
    • 使用:当检测到范围检查失败时调用,确保安全检查失败能够被正确处理。

总结

这段代码主要用于处理 /GS 安全检查失败和范围检查失败。通过捕获当前线程的上下文信息、查找函数入口点并展开调用栈,这些函数能够提供详细的调试信息,并确保在检测到安全问题时安全地终止进程。这些函数在安全调试和异常处理中非常有用,特别是对于防止堆栈缓冲区溢出攻击等安全威胁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值