【问题标题】:EIP value incorrect during buffer overflow缓冲区溢出期间 EIP 值不正确
【发布时间】:2012-06-20 07:35:37
【问题描述】:

我正在使用 ubuntu 12.04 和 64 位机器。我正在阅读一本关于缓冲区溢出的好书,在玩一个示例时发现了一个奇怪的时刻。

我有这个非常简单的 C 代码:

 void getInput (void){ 
    char array[8];    
    gets (array); 
    printf("%s\n", array); 

 }   
 main() { 
    getInput();    
    return 0;    
 }

在文件overflow.c中

我用 32 位标志编译它,因为书中的所有示例都假定为 32 位机器,我这样做是这样的

 gcc -fno-stack-protector -g -m32 -o ./overflow ./overflow.c

在代码中 char 数组只有 8 个字节,但反汇编时我发现该数组从堆栈上保存的 EBP 开始 16 个字节,所以我执行了这一行:

 printf "aaaaaaaaaaaaaaaaaaaa\x10\x10\x10\x20" | ./overflow

得到:

 aaaaaaaaaaaaaaaaaaaa 
 Segmentation fault (core dumped)

然后我打开核心文件:

 gdb ./overflow core
 #0  0x20101010 in ?? ()
 (gdb) info registers
 eax            0x19    25
 ecx            0xffffffff  -1
 edx            0xf77118b8  -143583048
 ebx            0xf770fff4  -143589388
 esp            0xffef6370  0xffef6370
 ebp            0x61616161  0x61616161
 esi            0x0 0
 edi            0x0 0
 eip            0x20101010  0x20101010

正如你所见,EIP 实际上获得了我想要的新价值。但是当我想输入一些有用的值时,比如 0x08048410

 printf "aaaaaaaaaaaaaaaaaaaa\x10\x84\x04\x08" | ./overflow

程序像往常一样崩溃,但是当我试图观察 EIP 寄存器中的值时会发生一些奇怪的事情:

 #0  0xf765be1f in ?? () from /lib/i386-linux-gnu/libc.so.6
 (gdb) info registers
 eax            0x61616151  1633771857
 ecx            0xf77828c4  -143120188
 edx            0x1 1
 ebx            0xf7780ff4  -143126540
 esp            0xff92dffc  0xff92dffc
 ebp            0x61616161  0x61616161
 esi            0x0 0
 edi            0x0 0
 eip            0xf765be1f  0xf765be1f

突然 EIP 开始看起来像这个 0xf765be1f,它看起来不像 0x08048410。事实上,我注意到将任何从 0 开始的十六进制值都足以得到这个崩溃的 EIP 值。你知道为什么会发生这种情况吗?是因为我是64位机吗?

UPD

cmets 的各位大侠询问更多信息,这里是getInput函数的反汇编:

 (gdb) disas getInput
 Dump of assembler code for function getInput:
    0x08048404 <+0>:    push   %ebp
    0x08048405 <+1>:    mov    %esp,%ebp
    0x08048407 <+3>:    sub    $0x28,%esp
    0x0804840a <+6>:    lea    -0x10(%ebp),%eax
    0x0804840d <+9>:    mov    %eax,(%esp)
    0x08048410 <+12>:   call   0x8048310 <gets@plt>
    0x08048415 <+17>:   lea    -0x10(%ebp),%eax
    0x08048418 <+20>:   mov    %eax,(%esp)
    0x0804841b <+23>:   call   0x8048320 <puts@plt>
    0x08048420 <+28>:   leave  
    0x08048421 <+29>:   ret 

【问题讨论】:

    标签: c 32bit-64bit buffer-overflow


    【解决方案1】:

    可能0x08048410处的代码被执行,跳转到0xf765be1f的区域。

    这个地址有什么?我猜它是一个函数(libC?),所以你可以检查它的汇编代码,看看它会做什么。

    另请注意,在成功运行中,您设法超出了 EBP,而不是 EIP。 EBP包含0x61616161,即aaaa,EIP包含0x20101010,即\n\n\n。似乎损坏的 EBP 间接导致 EIP 损坏。
    尝试使溢出的4个字节更长,然后它也应该溢出返回地址。

    【讨论】:

    • 听起来不是很有说服力。无论如何,0xf765be1f 是如何到达 EIP 的?有RET吗?无论如何,这需要更详细的调试。
    • @m0skit0,一旦你开始破坏堆栈并执行野地址,事情就变得非常不可预测。 0x08048410 处的代码可能不会简单地跳转到 0xf765be1f,但它可能会按照您的建议返回,或者通过寄存器调用函数。
    • 嗯,地址 0x08048410 只是在 getInput 函数中调用gets函数的地址,我只是想再次调用该函数,这是我重定向程序流程的确凿证据
    • 我确实相信在这两种情况下,EBP 和 EIP 寄存器都被正确覆盖,例如,当我在该 aaaa 字符串的末尾放置一个值 \x10\x10\x10\x20 时,eip 变为 0x20101010 ,如果我将其更改为 \x10\x84\x04\x20" 这几乎是正确的地址,除了最后一个十六进制值,我仍然在 EIP 中得到正确的表示 - 0x20048410,但是如果我将其更改为 \x10\x84\x04\x08 ,这是调用gets函数的正确有效地址我最终在我的EIP中得到0xf75a6e1f
    • 就是这样,我只是将 \x20 更改为 \x08,这足以在 EIP 中获得 mumbo-jumbo
    【解决方案2】:

    这可能是因为现代操作系统(Linux 至少可以,我不知道 Windows)和现代 libc have mechanisms 不允许执行堆栈中的代码。

    【讨论】:

    • 好吧,这并不能解释为什么第一个值 \x10\x10\x10\x20 被正确写入 EIP 寄存器,而 \x10\x84\x04\x08 却变成一团糟。
    • 确实如此:在第一个示例中,您并没有尝试跳转到有效地址,而在第二个示例中您这样做了。
    【解决方案3】:

    缓冲区溢出正在调用未定义的行为,因此任何事情都可能发生。推测可能发生的事情是徒劳的。

    【讨论】:

    • 好吧,这并没有解释为什么第一个值 \x10\x10\x10\x20 被正确写入 EIP 寄存器,而 \x10\x84\x04\x08 却变成一团糟跨度>
    • @RustamIssabekov This 可能会解释为什么会发生这种情况。 Here 你可能会发现一些奇特的堆栈粉碎。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-16
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    • 2013-11-06
    • 2013-04-11
    相关资源
    最近更新 更多