security cookie
在微软的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相关推荐
- Exploit Development – 使用SEH绕过Security Cookie
前面我们介绍在关闭/GS和DEP的情况下,如何利用栈溢出来实现exploit.下面我们会开启/GS,以及介绍突破/GS的常用手法. 我们先开启/GS,编译一个build,再试试原先的exploit,看 ...
- spring security http.rememberMe()使用和原理解析
spring security http.rememberMe()使用和原理解析 文章目录 spring security http.rememberMe()使用和原理解析 转载请贴上本文链接 htt ...
- 替换.DATA的COOKIE突破GS
首先 如果想直接覆盖 一场回调函数去劫持EXE的话 ,SafeSEH会阻止程序去执行: SafeSEH的原理很简单,就是对要调用的异常回调函数进行一系列对的有效性校验 需要 操作系统XP ...
- 《0day安全:软件漏洞分析技术》的一点总结
评价 首先评价一下这本书吧:(先抑后扬吧) 有些漏洞是win2000的,实在是太老了,难以进行实践,但是介绍一下也是很好的,但是不能实践理解得不深刻.[第一版是08年出版的,第二版是2011年,我手 ...
- 矛与盾:二进制漏洞攻防思想对抗
0×0二进制漏洞 二进制漏洞是可执行文件(PE.ELF文件等)因编码时考虑不周,造成的软件执行了非预期的功能.二进制漏洞早期主要以栈溢出为主,那时候操作系统和软件厂商还没有相应的安全意识,漏洞利用在当 ...
- CVE-2010-2883 从漏洞分析到样本分析
本文章将从漏洞利用分析开始,到样本分析结束,其中涉及到的知识点有PDF格式.TTF字体格式.缓冲区溢出漏洞利用.PE文件格式.软件脱壳和恶意代码分析.其中会演示一些基本操作,方便初学者进行复现. 前置 ...
- 个简单C++程序反汇编解析 (Rev. 3)
如果想要了解C++内部的实现原理,没有什么比观察C++代码对应的汇编代码来的更直接了.本系列主要从汇编角度研究C++代码和汇编的对应关系,揭示C++内部的机制和原理.在第一篇文章中我将从一个简单的C+ ...
- MVC5 - ASP.NET Identity登录原理 - Claims-based认证和OWIN
在Membership系列的最后一篇引入了ASP.NET Identity,看到大家对它还是挺感兴趣的,于是来一篇详解登录原理的文章.本文会涉及到Claims-based(基于声明)的认证,我们会详细 ...
- 转:C++反汇编揭秘2 – VC编译器的运行时错误检查(RTC)
作者: ATField Blog: http://blog.csdn.net/atfield 转载请注明出处 本文来自CSDN博客,转载请标明出处:http://blog.csdn ...
最新文章
- 五分钟看懂XLNet基本思想以及为什么它优于BERT
- 排序算法笔记:堆排序 HeapSort in java
- 使用计算机软件进行电视剪辑称为,浙江省2008年4月高等教育自学考试影像与剪辑艺术试题...
- POJ1679 Luogu4180 次小生成树
- Swift傻傻分不清楚系列(四)基本运算符 o_O!???
- 160. 相交链表 golang
- 大数据分析实战-信用卡欺诈检测
- 强核问世:NVIDIA发布A100 80GB GPU,为AI超级计算带来全球最强GPU
- NIPS中稿,聊聊科研!
- 1.5.1 Number Triangles 数字金字塔
- Java web 项目读取src或者tomcat下class文件夹下的xml文件或者properties文件
- 周立功CAN通讯(txt格式) 报文解析
- 三维微分方程组四阶龙格库塔求解
- 让智能设备拯救你的颈椎——智能颈椎按摩仪
- 网络——局域网和广域网
- ping服务器时显示的ttl是什么意思,ping命令显示的TTL是什么意思?
- 使用gcov和lcov测试代码覆盖率
- 满足国六标准通用型故障诊断仪:Q-OBD
- 西普实验吧CTF-Hashkill
- Civil 3d 数据快捷方式的使用