免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1535 | 回复: 0
打印 上一主题 下一主题

缓冲区溢出系列三之剖析gcc4以上版本对缓冲区溢出的保护 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-12-02 11:12 |只看该作者 |倒序浏览

前面说过,gcc4以上版本会对缓冲区溢出做出保护,那么这篇文章旨在使大家明白gcc到底是怎么做保护的。
我们在
《缓冲区溢出系列二之缓冲区溢出实例详解》
中提到过,用gcc4以上版本编译的时候,可以用选项-fno-stack-protector来关闭对缓冲区溢出的保护,那么我们现在就先来对比一下没做保护和做了保护到底有什么区别。
分别加上保护和不加保护来编译
《缓冲区溢出系列二之缓冲区溢出实例详解》
中的源程序p.c
xulei@xulei-desktop:~/bufferoverflow$ gcc -o noprotect p.c -fno-stack-protect
xulei@xulei-desktop:~/bufferoverflow$ gcc -o protect p.c
分别得到了不带保护的目标文件noprotect和带保护的目标文件protect。
然后用gdb反汇编一下,看看他们的汇编代码到底有什么不同
无缓冲区溢出保护的情况下:
xulei@xulei-desktop:~/bufferoverflow$ gdb noprotect
(gdb) disas main
Dump of assembler code for function main:
0x08048421 :  lea 0x4(%esp),%ecx
0x08048425 :    and $0xfffffff0,%esp
0x08048428 :    pushl -0x4(%ecx)
0x0804842b :    push %ebp
0x0804842c :    mov %esp,%ebp
0x0804842e :    push %ecx
0x0804842f :    sub $0x14,%esp
0x08048432 :    mov %ecx,-0xc(%ebp)
0x08048435 :    mov -0xc(%ebp),%eax
0x08048438 :    cmpl $0x2,(%eax)
0x0804843b :    jne 0x8048452  
0x0804843d :    mov -0xc(%ebp),%edx
0x08048440 :    mov 0x4(%edx),%eax
0x08048443 :    add $0x4,%eax
0x08048446 :    mov (%eax),%eax
0x08048448 :    mov %eax,(%esp)
0x0804844b :    call 0x80483f4  
0x08048450 :    jmp 0x804846a  
0x08048452 :    mov -0xc(%ebp),%edx
0x08048455 :    mov 0x4(%edx),%eax
0x08048458 :    mov (%eax),%eax
0x0804845a :    mov %eax,0x4(%esp)
0x0804845e :    movl $0x804854b,(%esp)
0x08048465 :    call 0x804832c  
0x0804846a :    add $0x14,%esp
0x0804846d :    pop %ecx
0x0804846e :    pop %ebp
0x0804846f :    lea -0x4(%ecx),%esp
0x08048472 :    ret
End of assembler dump.
(gdb) disas vulFunc
Dump of assembler code for function vulFunc:
0x080483f4 :    push %ebp
0x080483f5 :    mov %esp,%ebp
0x080483f7 :    sub $0x18,%esp
0x080483fa :    mov 0x8(%ebp),%eax
0x080483fd :    mov %eax,0x4(%esp)
0x08048401 :    lea -0xa(%ebp),%eax
0x08048404 :    mov %eax,(%esp)
0x08048407 :    call 0x804831c  
0x0804840c :    lea -0xa(%ebp),%eax
0x0804840f :    mov %eax,0x4(%esp)
0x08048413 :    movl $0x8048540,(%esp)
0x0804841a :    call 0x804832c  
0x0804841f :    leave
0x08048420 :    ret
End of assembler dump.
(gdb)

有缓冲区溢出保护的情况下:

xulei@xulei-desktop:~/bufferoverflow$ gdb protect
(gdb) disas main
Dump of assembler code for function main:
0x080484a3 :    lea 0x4(%esp),%ecx
0x080484a7 :    and $0xfffffff0,%esp
0x080484aa :    pushl -0x4(%ecx)
0x080484ad :    push %ebp
0x080484ae :    mov %esp,%ebp
0x080484b0 :    push %ecx
0x080484b1 :    sub $0x14,%esp
0x080484b4 :    mov %ecx,-0xc(%ebp)
0x080484b7 :    mov -0xc(%ebp),%eax
0x080484ba :    cmpl $0x2,(%eax)
0x080484bd :    jne 0x80484d4  
0x080484bf :    mov -0xc(%ebp),%edx
0x080484c2 :    mov 0x4(%edx),%eax
0x080484c5 :    add $0x4,%eax
0x080484c8 :    mov (%eax),%eax
0x080484ca :    mov %eax,(%esp)
0x080484cd :    call 0x8048454  
0x080484d2 :    jmp 0x80484ec  
0x080484d4 :    mov -0xc(%ebp),%edx
0x080484d7 :    mov 0x4(%edx),%eax
0x080484da :    mov (%eax),%eax
0x080484dc :    mov %eax,0x4(%esp)
0x080484e0 :    movl $0x80485cb,(%esp)
0x080484e7 :    call 0x8048374  
0x080484ec :    add $0x14,%esp
0x080484ef :    pop %ecx
0x080484f0 :    pop %ebp
0x080484f1 :    lea -0x4(%ecx),%esp
0x080484f4 :    ret
End of assembler dump.
(gdb) disas vulFunc
Dump of assembler code for function vulFunc:
0x08048454 :    push %ebp
0x08048455 :    mov %esp,%ebp
0x08048457 :    sub $0x28,%esp
0x0804845a :    mov 0x8(%ebp),%eax
0x0804845d :    mov %eax,-0x14(%ebp)
0x08048460 :    mov %gs:0x14,%eax
0x08048466 :    mov %eax,-0x4(%ebp)
0x08048469 :    xor %eax,%eax
0x0804846b :    mov -0x14(%ebp),%eax

0x0804846e :    mov %eax,0x4(%esp)
0x08048472 :    lea -0xe(%ebp),%eax
0x08048475 :    mov %eax,(%esp)
0x08048478 :    call 0x8048364  
0x0804847d :    lea -0xe(%ebp),%eax
0x08048480 :    mov %eax,0x4(%esp)
0x08048484 :    movl $0x80485c0,(%esp)
0x0804848b :    call 0x8048374  
0x08048490 :    mov -0x4(%ebp),%eax
0x08048493 :    xor %gs:0x14,%eax
0x0804849a :    je 0x80484a1  
0x0804849c :    call 0x8048384

0x080484a1 :    leave
0x080484a2 :    ret
End of assembler dump.
通过对比发现main函数反汇编以后都一样,不同的是vulFun函数反汇编以后,加保护的多了几条语句(上面用红色标出的即是)。
那么这几条语句就是gcc4以上版本对缓冲区溢出攻击做出了保护了,找到我们要研究问题的对象了,那么下来再针对这几条汇编代码进行研究,也就不难办到了。
稍微解释一下以上红色的那几行代码
0x0804845d :     mov    %eax,-0x14(%ebp)
0x08048460 :   mov    %gs:0x14,%eax
0x08048466 :   mov    %eax,-0x4(%ebp)
0x08048469 :   xor    %eax,%eax
0x0804846b :   mov    -0x14(%ebp),%eax
首先,将eax的内容暂时放入ebp-0x14这个内存地址处
然后下面两句是将%gs:0x14的内容放入ebp-0x4这个内存地址处
最后两句是再将原eax的值(暂存在ebp-0x14中的值)恢复。
可以看出加保护以后,只是在将eax压栈之间,先压入%gs:0x14的内容。
那么%gs:0x14里面是什么东西呢?
gs寄存器是32位x86的6个段寄存器(ES、CS、SS、DS、FS和GS)中的一个,大家可能比较熟悉16位的x86下的4个段寄存器(ES、CS、SS、DS),32位的多了两个段寄存器FS和GS。
经查阅资料,gcc4以上版本对缓冲区溢出的保护机制是这样的:在调用strcpy等一系列需要传递字符串参数的函数时,在压入传递进来的字符串参数前,先压入一个随即数(这里即%gs:0x14),然后在函数返回时再检测一下%gs:0x14和堆栈中原先压入的值是不是一致的,如果不一致,那么肯定有缓冲区溢出攻击。
由于这个随即值在栈中的位置是位于返回地址和传递的字符串参数之间的,所以要利用缓冲区溢出攻击来覆盖返回地址,那么就肯定也覆盖了这个随即值。
来看看vulFunc函数调用返回时的代码吧。
0x08048490 :   mov    -0x4(%ebp),%eax
0x08048493 :   xor    %gs:0x14,%eax
0x0804849a :    je     0x80484a1
0x0804849c :    call   0x8048384
果然,先将以前压栈的随即值和gs寄存器里的进行比较,如果不相同,则调用stack_chk_fail,那么如果到这一步,程序基本上也就崩了,缓冲区溢出的美梦也就在瞬间破灭了。

以上是在理论上讲解了一下gcc4以上版本对缓冲区溢出攻击做出的保护,下面,具体用gdb跟踪一下,看一看内存里的具体情况。
我们直接调到strcpy函数之后,来看看内存里的情况

(gdb) b *0x0804847d
Breakpoint 2 at 0x804847d
(gdb) c
Continuing.
Breakpoint 2, 0x0804847d in vulFunc ()
(gdb) i r
eax            0xbffff4ca -1073744694
ecx            0xbffff4c9 -1073744695
edx            0x9     9
ebx            0xb7fcbff4       -1208172556
esp            0xbffff4b0 0xbffff4b0
ebp            0xbffff4d8       0xbffff4d8
esi            0x8048510  134513936
edi            0x80483a0 134513568
eip            0x804847d 0x804847d
eflags         0x200246   [ PF ZF IF ID ]
cs             0x73    115
ss             0x7b     123
ds             0x7b    123
es             0x7b    123
fs             0x0       0
gs             0x33    51

可以看到这时候ebp是 0xbffff4d8,而从源代码
0x08048460 :   mov    %gs:0x14,%eax
0x08048466 :   mov    %eax,-0x4(%ebp)
中可以看出,%gs:0x14是存放在了内存地址ebp-0x4(=0xbffff4d4)中了,所以, 0xbffff4d4中就是%gs-0x14的内容了,看看内存

(gdb) x/40x $esp
0xbffff4b0:  0xbffff4ca    0xbffff706   0x00000000 0x00000000
0xbffff4c0:  0x00000000 0xbffff706   0x4141f6e3  0x41414141
0xbffff4d0:  0xb7004141 0x03133000 0xbffff4f8    0x080484d2
0xbffff4e0:  0xbffff706   0x08049ff4  0xbffff508   0xbffff510
0xbffff4f0:   0xb7ff0f50   0xbffff510   0xbffff568   0xb7e88685
0xbffff500:  0x08048510 0x080483a0 0xbffff568   0xb7e88685
0xbffff510:  0x00000002 0xbffff594   0xbffff5a0   0xb7fe2b38
0xbffff520:  0x00000001 0x00000001 0x00000000 0x08048270
0xbffff530:  0xb7fcbff4   0x08048510 0x080483a0 0xbffff568
0xbffff540:  0xd98a2179 0xf76c9569  0x00000000 0x00000000

可以看出%gs-0x14的内容是紫色标出的 0x03133000。由本人的经验粉红色的0x080484d2是函数vulFunc的返回地址,如果看过
《缓冲区溢出系列二之缓冲区溢出实例详解》
还没这个经验的话,那我讲得就太失败了。不过,也可以看看main的反汇编代码,看看0x080484d2是不是call   0x8048454 后面的那条指令,如果是,那就它就是返回地址无疑了。而浅蓝色标出的8个41个一个00就是我们的参数字符串AAAAAAAA。现在可以很清楚的看到%gs-0x14的内容的 0x03133000是位于参数和返回地址之间了吧。这次要进行缓冲区溢出攻击是不是就不那么容易了(至少我是没有成功的攻击过)。

下面说说本人的一些想法吧,纯属扯淡,可以不看。
在gcc保护模式下要进行缓冲区溢出攻击的话,就我自己的理解,要修改返回地址,有两种途径。
第一,你可以很准确的定位到返回地址在内存中的位置,这样的话就只修改存放返回地址的这一块内存就行了,其他原封不动,不过准确定位感觉在实际中比较困难;
第二,可以象常规方法那样覆盖从参数到返回地址甚至再向后覆盖,不过,如果你同时能修改gs寄存器中的值,使它和内存中相应地址的值一致就OK了。具体能不能实现,我没有试过,不过估计gs寄存器是不能随便让程序员动的。

如果你有什么见解,欢迎留言!





本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/86590/showart_1675220.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP