GS安全编译选项原理分析
GS编译选项的文件为gs_support.c 这是源码
/*** *gs_support.c - initialize the global buffer overrun security cookie * * Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: * Define __security_init_cookie, which is called at startup to initialize * the global buffer overrun security cookie used by the /GS compile flag. * *******************************************************************************/ #include <Windows.h> #if defined (_M_IX86) && defined (_CRTBLD) && defined (_DEBUG) /* * __security_init_cookie must be called before any exception handlers using * the cookie are registered. We do a spot check for this condition in the * debug version of the x86 CRT. */ #define CHECK_FOR_LATE_COOKIE_INIT #define EXCEPTION_CHAIN_END ((struct _EXCEPTION_REGISTRATION_RECORD * POINTER_32)-1) EXCEPTION_DISPOSITION __cdecl _except_handler4( IN struct _EXCEPTION_RECORD *ExceptionRecord, IN PVOID EstablisherFrame, IN OUT struct _CONTEXT *ContextRecord, IN OUT PVOID DispatcherContext ); #endif /* defined (_M_IX86) && defined (_CRTBLD) && defined (_DEBUG) */ /* * Default value used for the global /GS security cookie, defined here and * in gs_cookie.c (since standalone SDK build can't use CRT's internal.h). */ #ifdef _WIN64 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232 #else /* _WIN64 */ #define DEFAULT_SECURITY_COOKIE 0xBB40E64E #endif /* _WIN64 */ /* * The global security cookie. This name is known to the compiler. */ extern UINT_PTR __security_cookie; extern UINT_PTR __security_cookie_complement; /* * Union to facilitate converting from FILETIME to unsigned __int64 */ typedef union { unsigned __int64 ft_scalar; FILETIME ft_struct; } FT; /*** *__get_entropy() - retrieve entropy from the underlying OS. * *Purpose: * Static helper to encapsulate entropy extraction from the OS. * Combine a number of sources of randomness. * *Entry: * *Exit: * *Exceptions: * *******************************************************************************/ /* * Enclaves initialize the stack cookie in the loader (similar to all * modern platforms), but do not expose entropy. No attempt should be made * to reinitialize the cookie by harvesting new entropy. */ #if defined (_SCRT_ENCLAVE_BUILD) static UINT_PTR __get_entropy(void) { return DEFAULT_SECURITY_COOKIE; } #else static UINT_PTR __get_entropy(void) { UINT_PTR cookie; FT systime = { 0 }; LARGE_INTEGER perfctr; GetSystemTimeAsFileTime(&systime.ft_struct); #if defined (_WIN64) cookie = systime.ft_scalar; #else /* defined (_WIN64) */ cookie = systime.ft_struct.dwLowDateTime; cookie ^= systime.ft_struct.dwHighDateTime; #endif /* defined (_WIN64) */ cookie ^= GetCurrentThreadId(); cookie ^= GetCurrentProcessId(); #if _CRT_NTDDI_MIN >= NTDDI_VISTA #if defined (_WIN64) cookie ^= (((UINT_PTR)GetTickCount64()) << 56); #endif /* defined (_WIN64) */ cookie ^= (UINT_PTR)GetTickCount64(); #endif /* _CRT_NTDDI_MIN >= NTDDI_VISTA */ QueryPerformanceCounter(&perfctr); #if defined (_WIN64) cookie ^= (((UINT_PTR)perfctr.LowPart << 32) ^ perfctr.QuadPart); #else /* defined (_WIN64) */ cookie ^= perfctr.LowPart; cookie ^= perfctr.HighPart; #endif /* defined (_WIN64) */ /* * Increase entropy using ASLR relocation */ cookie ^= (UINT_PTR)&cookie; #if defined (_WIN64) /* * On Win64, generate a cookie with the most significant word set to zero, * as a defense against buffer overruns involving null-terminated strings. * Don't do so on Win32, as it's more important to keep 32 bits of cookie. */ cookie &= 0x0000FFFFffffFFFFi64; #endif /* defined (_WIN64) */ return cookie; } #endif /*** *__security_init_cookie() - init buffer overrun security cookie. * *Purpose: * Initialize the global buffer overrun security cookie which is used by * the /GS compile switch to detect overwrites to local array variables * that potentially corrupt the return address. This routine is called * at EXE/DLL startup. * *Entry: * *Exit: * *Exceptions: * *******************************************************************************/ void __cdecl __security_init_cookie(void) { UINT_PTR cookie; /* * Do nothing if the global cookie has already been initialized. On x86, * reinitialize the cookie if it has been previously initialized to a * value with the high word 0x0000. Some versions of Windows will init * the cookie in the loader, but using an older mechanism which forced the * high word to zero. */ if (__security_cookie != DEFAULT_SECURITY_COOKIE #if defined (_M_IX86) && (__security_cookie & 0xFFFF0000) != 0 #endif /* defined (_M_IX86) */ ) { __security_cookie_complement = ~__security_cookie; return; } /* * Initialize the global cookie with an unpredictable value which is * different for each module in a process. */ cookie = __get_entropy(); /* * Make sure the cookie is initialized to a value that will prevent us from * reinitializing it if this routine is ever called twice. */ if (cookie == DEFAULT_SECURITY_COOKIE) { cookie = DEFAULT_SECURITY_COOKIE + 1; } #if defined (_M_IX86) else if ((cookie & 0xFFFF0000) == 0) { cookie |= ( (cookie|0x4711) << 16); } #endif /* defined (_M_IX86) */ __security_cookie = cookie; __security_cookie_complement = ~cookie; }
要说的是 32位默认的值是0xBB40E64E 64位0x00002B992DDFA232
直接看反汇编也很明显
.text:004135E0 PerformanceCount= LARGE_INTEGER ptr -14h .text:004135E0 SystemTimeAsFileTime= _FILETIME ptr -0Ch .text:004135E0 var_4 = dword ptr -4 .text:004135E0 .text:004135E0 push ebp .text:004135E1 mov ebp, esp .text:004135E3 sub esp, 14h .text:004135E6 xor eax, eax .text:004135E8 mov [ebp+SystemTimeAsFileTime.dwLowDateTime], eax .text:004135EB mov [ebp+SystemTimeAsFileTime.dwHighDateTime], eax .text:004135EE lea ecx, [ebp+SystemTimeAsFileTime] .text:004135F1 push ecx ; lpSystemTimeAsFileTime .text:004135F2 call ds:GetSystemTimeAsFileTime .text:004135F8 mov edx, [ebp+SystemTimeAsFileTime.dwLowDateTime] .text:004135FB mov [ebp+var_4], edx .text:004135FE mov eax, [ebp+var_4] .text:00413601 xor eax, [ebp+SystemTimeAsFileTime.dwHighDateTime] .text:00413604 mov [ebp+var_4], eax .text:00413607 call ds:GetCurrentThreadId .text:0041360D xor eax, [ebp+var_4] .text:00413610 mov [ebp+var_4], eax .text:00413613 call ds:GetCurrentProcessId .text:00413619 xor eax, [ebp+var_4] .text:0041361C mov [ebp+var_4], eax .text:0041361F lea ecx, [ebp+PerformanceCount] .text:00413622 push ecx ; lpPerformanceCount .text:00413623 call ds:QueryPerformanceCounter .text:00413629 mov edx, [ebp+var_4] .text:0041362C xor edx, dword ptr [ebp+PerformanceCount] .text:0041362F mov [ebp+var_4], edx .text:00413632 mov eax, [ebp+var_4] .text:00413635 xor eax, dword ptr [ebp+PerformanceCount+4] .text:00413638 mov [ebp+var_4], eax .text:0041363B mov ecx, [ebp+var_4] .text:0041363E lea edx, [ebp+var_4] .text:00413641 xor ecx, edx .text:00413643 mov [ebp+var_4], ecx .text:00413646 mov eax, [ebp+var_4] .text:00413649 mov esp, ebp .text:0041364B pop ebp .text:0041364C retn .text:0041364C sub_4135E0 endp .text:0041364C
security_cookie 32位计算方式就是
- 获得 system time
- 与 GetCurrentProcessId() 异或
- 与 GetCurrentThreadId() 异或
- 与 GetTickCount() 异或
- 与 QueryPerformanceCounter()异或
64位的可以看原码大同小异
绕过方法也大同小异
1虚表,
2攻击seh,
3读到security_cookie,
4在运行前篡改security_cookie,
5劫持GetSystemTimeAsFileTime,
6,溢出1字节篡改security_cookie,在启动是就不会重新刷新cookie 第二次攻击就可以溢出
这里通过第三方劫持篡改security_cookie的值
从此山高路远,纵马扬鞭。愿往后旅途,三冬暖,春不寒,天黑有灯,下雨有伞。此生尽兴,不负勇往。