当前位置:编程学习 > 网站相关 >>

一个小程序的栈溢出

看下面代码:

 
 
[cpp]
#include <stdio.h> 
 
int cp (char *p) 

    int a; 
    char b[8]; 
    a=strcmp(p,"1234567"); 
    strcpy(b,p); 
    return a; 

 
int main() 

    int v=0; 
    char p[1024]; 
    while(1) 
    { 
        printf("please input password:       "); 
        scanf("%s",p);   
        v = cp(p); 
        if(v) 
        { 
            printf("incorrect password!\n\n"); 
        } 
        else 
        { 
            printf("Congralations \n\n"); 
            break; 
        } 
    } 
    return 0; 

 
 
 
在vs2008下面建个工程,我输入“1234567”的时候输出是“Congralations ”,程序是正确的,但是当我输入是“12345678”的时候,崩溃了,于是我把GS关了,结果输出竟然也是“Congralations ”。我开始的时候很奇怪,于是我再试了下还是输出“Congralations ”。于是用OD调试了下····
 
首先输入是“1234567”的时候:

\




 
       这个是子函数cp ()里面的反汇编,程序停在了strcpy之后,这时候EAX(函数执行完的返回值)是0,下面的图是堆栈的情况,字符1对应的16进制是31,由于我是intel的cpu,所以是小端模式(高字节存在地位,低字节存在高位),[EBP-12]到[EBP-4]是数组b[8]的内存地址,从低到高依次存放了“1234567”和’\0′,而[EBP-4]存的是a的值,作为返回值,如果是0那么就代表密码输入正确,否则就失败。输入是“1234567”的情况下,结果子函数返回的是0,输出结果也是正确的。


\

 
然后我输入“12345678”的情况:
       这下就奇怪了,我们看寄存器EAX的值,竟然也是0!真是奇怪了,“12345678”明明比“1234567”大啊,strcmp返回的结果肯定是要比0大的额,再看看[EBP-4]的值也是0额(是它赋值给EAX的),这就意味着返回值a是0啊,按照正常结果返回值应该是大于0的数啊,奇怪了!我们再看看堆栈情况(下图),[EBP-12]到[EBP-4]是数组b[8]的内存地址,从低到高依次存放了“12345678”,那么‘\0’呢?这里已经是栈溢出了,b[8]只有八个字节,只能存取7个字符+’\0′,现在存取了八个字节+’\0′,肯定溢出了。cpu存取的时候是从低地址到高地址的,也就是说[EBP-4]这个字节里面存的应该是’\0′,但是[EBP-4]本来存的是strcmp的返回值啊,原本是大于0 的数,这下被strcpy执行的时候的’\0′覆盖了,所以[EBP-4]这个字节就变成了0。自然程序输出就有问题了。



\

 

 

最后是输入”123456789″的时候:

 

      按照上面的推论,输入”123456789″的时候,在子函数里,[EBP-12]到[EBP-4]是数组b[8]的内存地址,从低到高依次存放了“12345678”,而[EBP-4]字节里面存的应该是’9′的十六进制39,[EBP-3]存取的是’\0′的十六进制0,再后面两个字节也是0。那么CPU读取的时候从高到底低读取,读出来的结果就是00000039,也就是39,那么返回值也就是39。下面实际的结果:

\

呵呵,果然如此!这下就搞明白了~~~

上面的程序也只是一个例子来演示栈溢出的结果,实际上,在溢出的时候甚至可以覆盖你的EIP,然后马上HOOK到自己的恶意程序,所以一定要小心栈溢出!

博主新地址 www.firefoxbug.net

补充:综合编程 , 安全编程 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,