基本代码:
/***
*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); /* 报告范围检查失败 */
}
代码分析
-
capture_current_context
函数:- 功能:捕获当前线程的上下文信息,并尝试查找当前指令指针对应的函数入口点,然后展开调用栈。
- 使用:用于调试和异常处理,获取当前函数的上下文信息。
-
capture_previous_context
函数:- 功能:捕获前一个调用栈帧的上下文信息,并尝试展开调用栈。
- 使用:用于获取前一个函数的上下文信息,以便更好地理解调用栈。
-
__raise_securityfailure
函数:- 功能:处理
/GS
安全检查失败,触发调试器钩子,记录调试器是否存在,调用未处理异常处理函数,最后终止进程。 - 使用:在检测到
/GS
安全检查失败时调用,确保进程安全终止并提供调试信息。
- 功能:处理
-
__report_gsfailure
函数:- 功能:报告堆栈保护 cookie 检查失败,设置异常记录和上下文记录,然后调用
__raise_securityfailure
函数处理异常。 - 使用:当检测到堆栈保护 cookie 被篡改时调用,确保安全检查失败能够被正确处理。
- 功能:报告堆栈保护 cookie 检查失败,设置异常记录和上下文记录,然后调用
-
__report_securityfailureEx
函数:- 功能:报告特定的安全检查失败,支持多个参数,设置异常记录和上下文记录,然后调用
__raise_securityfailure
函数处理异常。 - 使用:当需要报告带有额外参数的安全检查失败时调用,提供更多调试信息。
- 功能:报告特定的安全检查失败,支持多个参数,设置异常记录和上下文记录,然后调用
-
__report_securityfailure
函数:- 功能:报告特定的安全检查失败,设置异常记录和上下文记录,然后调用
__raise_securityfailure
函数处理异常。 - 使用:当检测到特定的安全检查失败时调用,确保安全检查失败能够被正确处理。
- 功能:报告特定的安全检查失败,设置异常记录和上下文记录,然后调用
-
__report_rangecheckfailure
函数:- 功能:报告范围检查失败,调用
__report_securityfailure
函数处理异常。 - 使用:当检测到范围检查失败时调用,确保安全检查失败能够被正确处理。
- 功能:报告范围检查失败,调用
总结
这段代码主要用于处理 /GS
安全检查失败和范围检查失败。通过捕获当前线程的上下文信息、查找函数入口点并展开调用栈,这些函数能够提供详细的调试信息,并确保在检测到安全问题时安全地终止进程。这些函数在安全调试和异常处理中非常有用,特别是对于防止堆栈缓冲区溢出攻击等安全威胁。