在微软的c/c++ 编译器中,增加了对于栈溢出进行检测的参数“/GS”,在调试shellcode 的时候,发现vs2005 产生的code 和 vc6 产生的code 有些不同,才让我注意到这个问题。

写了这样的一个测试程序:

void foo(const char * datas)

{

char szbuf[32];

strcpy(szbuf, datas);

}

汇编的代码如下:

00411F70  push        ebp

00411F71  mov         ebp,esp

00411F73  sub         esp,0ECh

00411F79  push        ebx

00411F7A  push        esi

00411F7B  push        edi

00411F7C  lea         edi,[ebp-0ECh]

00411F82  mov         ecx,3Bh

00411F87  mov         eax,0CCCCCCCCh ;0x0c is equal to the machine code of int3

00411F8C  rep stos    dword ptr es:[edi]

00411F8E  mov         eax,dword ptr [___security_cookie (419004h)]

00411F93  xor         eax,ebp

00411F95  mov         dword ptr [ebp-4],eax

00411F98  mov         eax,dword ptr [ebp+8]

00411F9B  push        eax

00411F9C  lea         ecx,[ebp-28h]

00411F9F  push        ecx

00411FA0  call        @ILT+625(_strcpy) (411276h)

00411FA5  add         esp,8 ; strcpy's call conversation is __cdecl, so the caller should help callee cleanup stack

00411FA8  push        edx

00411FA9  mov         ecx,ebp ; pass the stack top by ecx

00411FAB  push        eax

00411FAC  lea         edx,[ (411FD8h)] ; pointer to a _RTC_framedesc structure

00411FB2  call        @ILT+195(@_RTC_CheckStackVars@8) (4110C8h)

00411FB7  pop         eax

00411FB8  pop         edx

00411FB9  pop         edi

00411FBA  pop         esi

00411FBB  pop         ebx

00411FBC  mov         ecx,dword ptr [ebp-4]

00411FBF  xor         ecx,ebp

00411FC1  call        @ILT+45(@__security_check_cookie@4) (411032h)

00411FC6  add         esp,0ECh

00411FCC  cmp         ebp,esp

00411FCE  call        @ILT+430(__RTC_CheckEsp) (4111B3h)

00411FD3  mov         esp,ebp

00411FD5  pop         ebp

00411FD6  ret

00411FD7  nop

00411FD8  db          01h

00411FD9  db          00h

00411FDA  db          00h

00411FDB  db          00h

00411FDC  db          e0h

00411FDD  db          1fh

00411FDE  db          41h

00411FDF  db          00h

00411FE0  db          d8h

00411FE1  db          ffh

00411FE2  db          ffh

00411FE3  db          ffh

00411FE4  db          20h

00411FE5  db          00h

00411FE6  db          00h

00411FE7  db          00h

00411FE8  db          ech

00411FE9  db          1fh

00411FEA  db          41h

00411FEB  db          00h

00411FEC  db          62h

00411FED  db          75h

00411FEE  db          66h

00411FEF  db          66h

00411FF0  db          65h

00411FF1  db          72h

00411FF2  db          00h

从程序可以看出在函数被调用之后,在正确的把ebp压入stack 之后,把当前的esp存储到ebp 中,在往下就是这个函数体自身需要的stack 空间了,微软的编译器会在debug 版本的程序中,在每一个函数的堆栈顶分配一定数目的空间,把int3的机器码写入,这样做的目的是可以防止程序跑飞,如果程序跑飞,且eip落入这个空间,那么取出的指令都是int 3,从而能程序被中断。

___security_cookie 变量是一个 UINT_PTR 类型的数值,这个数值应该被编译到bufferoverflowU.lib 这个库中,数值的初始值定义如下:

#ifdef _WIN64

#define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232

#else  /* _WIN64 */

#define DEFAULT_SECURITY_COOKIE 0xBB40E64E

#endif  /* _WIN64 */

DECLSPEC_SELECTANY UINT_PTR __security_cookie = DEFAULT_SECURITY_COOKIE;

函数在取到该值之后,会和当前的ebp 相异或(xor),异或的值保持在stack 的顶部。在函数的体被执行完成之后,__security_check_cookie 会被调用,来检测security cookie 是否被修改过,__security_check_cookie 函数需要一个参数,不过这个参数没有使用,函数中,只是把ecx 的值和 _security_cookie 的值相比较,看看是否相同,如果不相同则认定为stack overflow。从上面的汇编代码可以看出在调用_security_check_cookie 之前,就把_security_cookie 的值取到ecx 中,且与ebp 进行异或(xor)操作。这样通常能够很好的防范stack 的overflow,通常的exploit code 都要覆盖函数的返回地址,而覆盖过程中写入的stack 的值是基本不会等于(__security_cookie & ebp ) 的值。

其实在调用 _security_check_cookie 函数之前,还调用了函数 _RTC_CheckStackVars,这个函数的原型是:

void   __fastcall _RTC_CheckStackVars(void *_Esp, _RTC_framedesc *_Fd);

其中_RTC_framedesc 结构为 :

typedef struct _RTC_framedesc {

int varCount;

_RTC_vardesc *variables;

} _RTC_framedesc;

_RTC_vardesc 的结构为:RTC 可能是run time check 的缩写,而 vardesc 可能是 variable descritpion 的缩写

typedef struct _RTC_vardesc {

int addr;

int size;

char *name;

} _RTC_vardesc;

_RTC_CheckStackVars 的汇编代码如下:

004122D0  push        ebp

004122D1  mov         ebp,esp

004122D3  push        ecx

004122D4  push        ebx

004122D5  push        esi

004122D6  push        edi

004122D7  xor         edi,edi

004122D9  mov         esi,edx

004122DB  cmp         dword ptr [esi],edi ;比较是否有数组变量

004122DD  mov         ebx,ecx             ; 需要比较的堆栈顶是通过ecx 传递进来的,把这个值保持到 ebx

004122DF  mov         dword ptr [i],edi  ; i 应该是记录当前比较了几个 _RTC_vardesc

004122E2  jle         _RTC_CheckStackVars+58h (412328h)  ;如果没有,则不必检测了,程序跳转退出

004122E4  mov         eax,dword ptr [esi+4]              ;eax 指向_RTC_vardesc 结构

004122E7  mov         ecx,dword ptr [eax+edi]            ;ecx 为 _RTC_vardesc.addr 的值

004122EA  add         eax,edi

004122EC  cmp         dword ptr [ecx+ebx-4],0CCCCCCCCh   ; 根据addr 算出堆栈中的一个地址,addr 的来历不详

004122F4  jne         _RTC_CheckStackVars+34h (412304h)  ; 如果不是初始化的 0xCCCCCCCC ; 报错

004122F6  mov         edx,dword ptr [eax+4]

004122F9  add         edx,ecx

004122FB  cmp         dword ptr [edx+ebx],0CCCCCCCCh

00412302  je          _RTC_CheckStackVars+48h (412318h)

00412304  mov         eax,dword ptr [esi+4]

00412307  mov         ecx,dword ptr [eax+edi+8]

0041230B  mov         edx,dword ptr [ebp+4]

0041230E  push        ecx

0041230F  push        edx

00412310  call        _RTC_StackFailure (411127h)

00412315  add         esp,8

00412318  mov         eax,dword ptr [i]

0041231B  add         eax,1

0041231E  add         edi,0Ch

00412321  cmp         eax,dword ptr [esi]

00412323  mov         dword ptr [i],eax

00412326  jl          _RTC_CheckStackVars+14h (4122E4h)

00412328  pop         edi

00412329  pop         esi

0041232A  pop         ebx

0041232B  mov         esp,ebp

0041232D  pop         ebp

0041232E  ret

从函数的汇编代码可以看出虽然 CheckStackVars 需要两个参数,但是函数并没有使用这两个参数,而实际需要检测的数值,是通过edx、ecx 两个寄存器传递的,edx 指向一个_RTC_framedesc 的结构,ecx 指向函数的堆栈的顶部,可见编译器在每一个函数的结束处添加了一个_RTC_framedesc 的对象。

_RTC_framedesc 结构,好在只是记录函数中用到的数组变量的情况。上面的 _RTC_framedesc 值为:

_RTC_framedesc.varCount = 1;

_RTC_framedesc.variables = 0x00411fe0

_RTC_vardesc.addr = 0xFFFFFFD8  /* -40 */

_RTC_vardesc.size = 0x00000020 /* buffer size is : 0x20 */

_RTC_vardesc.name = 0x00411fec /* poiner to string 'buffer' */

security cookie相关推荐

  1. Exploit Development – 使用SEH绕过Security Cookie

    前面我们介绍在关闭/GS和DEP的情况下,如何利用栈溢出来实现exploit.下面我们会开启/GS,以及介绍突破/GS的常用手法. 我们先开启/GS,编译一个build,再试试原先的exploit,看 ...

  2. spring security http.rememberMe()使用和原理解析

    spring security http.rememberMe()使用和原理解析 文章目录 spring security http.rememberMe()使用和原理解析 转载请贴上本文链接 htt ...

  3. 替换.DATA的COOKIE突破GS

    首先   如果想直接覆盖  一场回调函数去劫持EXE的话 ,SafeSEH会阻止程序去执行: SafeSEH的原理很简单,就是对要调用的异常回调函数进行一系列对的有效性校验    需要 操作系统XP ...

  4. 《0day安全:软件漏洞分析技术》的一点总结

    评价 首先评价一下这本书吧:(先抑后扬吧)  有些漏洞是win2000的,实在是太老了,难以进行实践,但是介绍一下也是很好的,但是不能实践理解得不深刻.[第一版是08年出版的,第二版是2011年,我手 ...

  5. 矛与盾:二进制漏洞攻防思想对抗

    0×0二进制漏洞 二进制漏洞是可执行文件(PE.ELF文件等)因编码时考虑不周,造成的软件执行了非预期的功能.二进制漏洞早期主要以栈溢出为主,那时候操作系统和软件厂商还没有相应的安全意识,漏洞利用在当 ...

  6. CVE-2010-2883 从漏洞分析到样本分析

    本文章将从漏洞利用分析开始,到样本分析结束,其中涉及到的知识点有PDF格式.TTF字体格式.缓冲区溢出漏洞利用.PE文件格式.软件脱壳和恶意代码分析.其中会演示一些基本操作,方便初学者进行复现. 前置 ...

  7. 个简单C++程序反汇编解析 (Rev. 3)

    如果想要了解C++内部的实现原理,没有什么比观察C++代码对应的汇编代码来的更直接了.本系列主要从汇编角度研究C++代码和汇编的对应关系,揭示C++内部的机制和原理.在第一篇文章中我将从一个简单的C+ ...

  8. MVC5 - ASP.NET Identity登录原理 - Claims-based认证和OWIN

    在Membership系列的最后一篇引入了ASP.NET Identity,看到大家对它还是挺感兴趣的,于是来一篇详解登录原理的文章.本文会涉及到Claims-based(基于声明)的认证,我们会详细 ...

  9. 转:C++反汇编揭秘2 – VC编译器的运行时错误检查(RTC)

    作者:      ATField Blog:      http://blog.csdn.net/atfield 转载请注明出处 本文来自CSDN博客,转载请标明出处:http://blog.csdn ...

最新文章

  1. 五分钟看懂XLNet基本思想以及为什么它优于BERT
  2. 排序算法笔记:堆排序 HeapSort in java
  3. 使用计算机软件进行电视剪辑称为,浙江省2008年4月高等教育自学考试影像与剪辑艺术试题...
  4. POJ1679 Luogu4180 次小生成树
  5. Swift傻傻分不清楚系列(四)基本运算符 o_O!???
  6. 160. 相交链表 golang
  7. 大数据分析实战-信用卡欺诈检测
  8. 强核问世:NVIDIA发布A100 80GB GPU,为AI超级计算带来全球最强GPU
  9. NIPS中稿,聊聊科研!
  10. 1.5.1 Number Triangles 数字金字塔
  11. Java web 项目读取src或者tomcat下class文件夹下的xml文件或者properties文件
  12. 周立功CAN通讯(txt格式) 报文解析
  13. 三维微分方程组四阶龙格库塔求解
  14. 让智能设备拯救你的颈椎——智能颈椎按摩仪
  15. 网络——局域网和广域网
  16. ping服务器时显示的ttl是什么意思,ping命令显示的TTL是什么意思?
  17. 使用gcov和lcov测试代码覆盖率
  18. 满足国六标准通用型故障诊断仪:Q-OBD
  19. 西普实验吧CTF-Hashkill
  20. Civil 3d 数据快捷方式的使用

热门文章

  1. Android逆向之路---脱壳360加固
  2. jwt思维导图,让jwt不再难懂
  3. java开发常见的热词奇解
  4. 按照重复的次数高到低进行排序
  5. JS调用PageMethods(转)
  6. C++生成随机数:负二项分布/帕斯卡分布(negative binomial distribution)
  7. ip通信基础第九周(下)
  8. 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
  9. codeforce 570 problem E 51Nod-1503-猪和回文
  10. Java与WCF交互(一):Java客户端调用WCF服务