您好,欢迎来到刀刀网。
搜索
您的当前位置:首页深入C/C++之基于Cookie的安全检查(VS2005)

深入C/C++之基于Cookie的安全检查(VS2005)

来源:刀刀网

昨天在试着逆向一个有时间期限的LIB时,发现一些特别的检查函数,在之前的VC2003中是没有的,这些函数可谓是重量级函数。由于个人比较看不惯自己不懂的东西,出于不愤之情绪研究了下这些函数。首先在这里介绍个人认为较之其他几个更为重要的一种安全检查方式——基于Cookie的缓冲区溢出安全检查!

为了在发布版本中也能检测到缓冲区溢出,防止程序因缓冲区而受到攻击,VS2005(VC8)便增加了基于Cookie的安全检查。

在计算机领域,Cookie一词最早出现在网站开发中,是指网站的服务程序通过浏览器保存到客户端的少量数据,这些数据都是二进制的,或者是经过加密的,通常用来记录用户身份和登录情况等信息。后来这个词被泛指一方签发给另一方的认证或者标志信息。

#ifdef _WIN
         #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232
#else 

         #define DEFAULT_SECURITY_COOKIE 0xBB40EE
#endif 

DECLSPEC_SELECTANY UINT_PTR __security_cookie = DEFAULT_SECURITY_COOKIE;

DECLSPEC_SELECTANY UINT_PTR __security_cookie_complement = ~(DEFAULT_SECURITY_COOKIE);

上面说到最开始的时候被初始化为了0xBB40EE。言外之意后面还会对它进行处理?答案是肯定的!下一次初始化是在我们程序进入主函数之前的:__tmainCRTStartup函数里。

抛开预处理和机器的条件判断,这个函数的原型如下:

int mainCRTStartup( void )
{
        /*
         * The /GS security cookie must be initialized before any exception
         * handling targetting the current image is registered.  No function
         * using exception handling can be called in the current image until
         * after __security_init_cookie has been called.
         */
        __security_init_cookie();

        return __tmainCRTStartup();
}

我的机子抛开后是调用的这个函数。现在的硬件环境大多数也是这个。这里可以看到在这里会调用__security_init_cookie()这个函数对__security_cookie变量再次初始化。这个函数也是能看到原型的,它位于gs_support.c文件中。进去看看,抛开一编译时的判断条件其原型主体部分为:

void __cdecl __security_init_cookie()

{

    UINT_PTR cookie;
    FT systime={0};
    LARGE_INTEGER perfctr;

    GetSystemTimeAsFileTime(&systime.ft_struct);

    cookie = systime.ft_struct.dwLowDateTime;
    cookie ^= systime.ft_struct.dwHighDateTime;

    cookie ^= GetCurrentProcessId();
    cookie ^= GetCurrentThreadId();
    cookie ^= GetTickCount();

    QueryPerformanceCounter(&perfctr);

    cookie ^= perfctr.LowPart;
    cookie ^= perfctr.HighPart;

    __security_cookie = cookie;
    __security_cookie_complement = ~cookie;

}

这里可以看出来,为了取得好的随机性,先是取出时间,异或之,然后是分别跟其他一些列具有随机性的数据(进程ID,线程ID,TickCount和性能计数器)进行异或运算。这个变量因为是全局的,在这里( mainCRTStartup启动函数)初始化后在进程过程中将不会再改变。如果想要查看这个cookie变量的值。可以再调试的时候拉出“即时窗口(Immediate)”,在里面输入__security_cookie回车就能看到了。

好了,在上面介绍完了Cookie变量的产生、初始化和作用后,下面来看看使用。

写个最简单的测试:

int main( void )

{

    char a[ 20 ];

    strcpy( a, "masefee" );

    return 0;

}

上面说过,编译器会在可能发生缓冲区溢出的函数插入Cookie变量和安全检查。这样一个小例子足以让它检查了。他已经发现可能存在危险了。是不是很智能? - -

要看这个函数一开始怎么写入Cookie变量的,可以打断点在红色的括号处或者F11单步。这里又得在反汇编里面进行了,这里不厌其烦的从汇编里面去看问题,包括以前的文章基本跟汇编有联系。这里不是别的,只是个人认为还是很有必要从汇编的角度去了解高级语言的原理。很多是很必要的。当然这里也只能从汇编去分析这个Cookie变量的写入过程及检查过程!忍耐一下! - -

就这里这个简单的例子,DEBUG模式下反汇编如下:

 
0043BEF0  push        ebp  
0043BEF1  mov         ebp,esp 
0043BEF3  sub         esp,0E0h 
0043BEF9  push        ebx  
0043BEFA  push        esi  
0043BEFB  push        edi  
0043BEFC  lea         edi,[ebp-0E0h] 
0043BF02  mov         ecx,38h 
0043BF07  mov         eax,0CCCCCCCCh 
0043BF0C  rep stos    dword ptr es:[edi] 
0043BF0E  mov         eax,dword ptr [___security_cookie (4B7A74h)] 
0043BF13  xor         eax,ebp 
0043BF15  mov         dword ptr [ebp-4],eax 
0043BF18  push        offset string "masefee" (4AA938h) 
0043BF1D  lea         eax,[ebp-1Ch] 
0043BF20  push        eax  
0043BF21  call        @ILT+3880(_strcpy) (437F2Dh) 
0043BF26  add         esp,8 
0043BF29  xor         eax,eax 
0043BF2B  push        edx  
0043BF2C  mov         ecx,ebp 
0043BF2E  push        eax  
0043BF2F  lea         edx,[ (43BF5Ch)] 
0043BF35  call        @ILT+3115(@_RTC_CheckStackVars@8) (437C30h) 
0043BF3A  pop         eax  
0043BF3B  pop         edx  
0043BF3C  pop         edi  
0043BF3D  pop         esi  
0043BF3E  pop         ebx  
0043BF3F  mov         ecx,dword ptr [ebp-4] 
0043BF42  xor         ecx,ebp 
0043BF44  call        @ILT+920(@__security_check_cookie@4) (43739Dh) 

0043BF49  add         esp,0E0h 
0043BF4F  cmp         ebp,esp 
0043BF51  call        @ILT+7205(__RTC_CheckEsp) (438C2Ah) 
0043BF56  mov         esp,ebp 
0043BF58  pop         ebp  
0043BF59  ret             

这就是main函数的所有反汇编代码。首先看红色的一句指令。是将___security_cookie变量的值给取出来。然后蓝色的指令就是将取出来的Cookie全局变量与当前EBP的值进行异或运算。与EBP异或当然有好处。

1. 可以增加随机性,尽可能使不同函数的安全Cookie都不同。

2. 可以检查EBP是否被破坏,因为在函数结束检查Cookie时,还会将Cookie变量值再次与EBP异或,如果EBP的值没有变化,那么就能恢  复成原来的___security_cookie值。

这些细节地方不得不佩服微软的设计师们的缜密和扩展的思维!

下面一步就看最后的检查部分,粉色的部分前两句指令是将Cookie变量的值重新取出来并异或还原并保存到ECX中。保存到ECX是有目的的。之后再讨论。第三句粉色的CALL就是调用__security_check_cookie 函数了。其原型非常简单:

void __declspec(naked) __fastcall __security_check_cookie(UINT_PTR cookie)
{
    /* x86 version written in asm to preserve all regs */
    __asm

    {
        cmp ecx, __security_cookie
        jne failure
        rep ret /* REP to avoid AMD branch prediction penalty */
    failure:
        jmp __report_gsfailure
    }
}

好了,基本上写完了。上面留了两个点,一是main函数里面我有标志了一句橙色的语句,这个也是一个检查。将在后面的博文中提到。二是__report_gsfailure函数的整个过程。也将在后面的博文中深入阐述。上面有什么不对的地方还望大家批评。我很希望得到大家的指点!

思考:

      1. 这种模式的安全检查能够移植到我们平常的项目中的哪些地方,在我们用户代码上显示进行检查?

      2. 这种产生尽可能随机的方式用于类似于生成对象的全局唯一ID或者更多的需要唯一性的数据上?

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- gamedaodao.com 版权所有 湘ICP备2022005869号-6

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务