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位计算方式就是

  1. 获得 system time
  2. 与 GetCurrentProcessId() 异或
  3. 与 GetCurrentThreadId() 异或
  4. 与 GetTickCount() 异或
  5. 与 QueryPerformanceCounter()异或

 

64位的可以看原码大同小异

绕过方法也大同小异

1虚表,

2攻击seh,

3读到security_cookie,

4在运行前篡改security_cookie,

5劫持GetSystemTimeAsFileTime,

6,溢出1字节篡改security_cookie,在启动是就不会重新刷新cookie 第二次攻击就可以溢出

 

 这里通过第三方劫持篡改security_cookie的值  

 

posted @ 2021-11-25 10:51  紅人  阅读(313)  评论(0编辑  收藏  举报