Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 堆栈上的局部变量位置不变_C_Buffer Overflow - Fatal编程技术网

C 堆栈上的局部变量位置不变

C 堆栈上的局部变量位置不变,c,buffer-overflow,C,Buffer Overflow,我目前正在阅读一本关于安全漏洞的书,并来到了关于基于堆栈的缓冲区溢出的部分。它给出了一个类似于下面的例子 //overFlowTest.c #include <string.h> #include <stdio.h> #include <stdlib.h> void main(int argv, char* argv[]) { int i = 0; char buffer[4]; strcpy(buffer, argv[1]);

我目前正在阅读一本关于安全漏洞的书,并来到了关于基于堆栈的缓冲区溢出的部分。它给出了一个类似于下面的例子

//overFlowTest.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void main(int argv, char* argv[])
{
    int i = 0;
    char buffer[4];
    strcpy(buffer, argv[1]);
    if(i)
    {
        printf("overwrote i\n");
    }
}
但是当我改变局部变量的创建顺序时,我会认为它们会以相反的顺序被推到堆栈中,缓冲区溢出将不起作用

//overFlowTest.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void main(int argv, char* argv[])
{
    char buffer[4];
    int i = 0;
    strcpy(buffer, argv[1]);
    if(i)
    {
        printf("overwrote i\n");
    }
}

你知道为什么会发生这种情况吗?

所以,我在探索这个问题时发现了一些有趣的信息

第一,这个问题不是用叮当声重现的。当我编译第二个程序时,我没有看到如下所示的print语句:

$ clang so.c -o so.out
so.c:4:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main(int arg, char* argv[])
^
so.c:4:1: note: change return type to 'int'
void main(int arg, char* argv[])
^~~~
int
1 warning generated.

$ clang so2.c -o so2.out
so2.c:4:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main(int arg, char* argv[])
^
so2.c:4:1: note: change return type to 'int'
void main(int arg, char* argv[])
^~~~
int
1 warning generated.

$ ./so.out AAAAAAAAAAAAAAAAAAA
overwrote i

$ ./so2.out AAAAAAAAAAAAAAAAAAA

$
然而,如果我们对gcc也这样做,我们会发现它们都失败了

$ gcc so.c -o so.exe

$ gcc so2.c -o so2.exe

$ ./so.exe AAAAAAAAAAAAAAAA
overwrote i

$ ./so2.exe AAAAAAAAAAAAAAAA
overwrote i

$
再看远一点,让我们看看这些组件

$ gcc so.c -S -masm=intel

$ gcc so2.c -S -masm=intel

$ diff so.s so2.s
1c1
<       .file   "so.c"
---
>       .file   "so2.c"

$
$gcc so.c-S-masm=intel
$gcc so2.c-S-masm=intel
$diff so.s so2.s
1c1
<.file“so.c”
---
>.文件“so2.c”
$
正如您所看到的,这里唯一的区别是文件名(我也在关闭所有优化的情况下进行了测试,结果相同)

现在,让我们试试叮当声

$ clang -S -mllvm --x86-asm-syntax=intel so.c
so.c:4:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main(int arg, char* argv[])
^
so.c:4:1: note: change return type to 'int'
void main(int arg, char* argv[])
^~~~
int
1 warning generated.

$ clang -S -mllvm --x86-asm-syntax=intel so2.c
so2.c:4:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main(int arg, char* argv[])
^
so2.c:4:1: note: change return type to 'int'
void main(int arg, char* argv[])
^~~~
int
1 warning generated.

$ diff so.s so2.s
26c26
<       lea     rax, qword ptr [rbp - 24]
---
>       lea     rax, qword ptr [rbp - 20]
29c29
<       mov     dword ptr [rbp - 20], 0
---
>       mov     dword ptr [rbp - 24], 0
34c34
<       cmp     dword ptr [rbp - 20], 0
---
>       cmp     dword ptr [rbp - 24], 0

$
$clang-S-mllvm--x86 asm syntax=intel so.c
so.c:4:1:警告:“main”的返回类型不是“int”[-Wmain返回类型]
void main(int arg,char*argv[])
^
so.c:4:1:注意:将返回类型更改为“int”
void main(int arg,char*argv[])
^~~~
int
生成1个警告。
$clang-S-mllvm--x86 asm语法=英特尔so2.c
so2.c:4:1:警告:“main”的返回类型不是“int”[-Wmain返回类型]
void main(int arg,char*argv[])
^
so2.c:4:1:注:将退货类型更改为“int”
void main(int arg,char*argv[])
^~~~
int
生成1个警告。
$diff so.s so2.s
26c26
lea rax,qword ptr[rbp-20]
29c29
mov dword ptr[rbp-24],0
34c34
cmp dword ptr[rbp-24],0
$
看起来clang将这两个文件编译成了不同的版本;这可以防止我被覆盖


总之,这两个文件产生不同输出的原因是因为代码产生未定义的行为-编译器不受任何标准的约束,可以产生任何最简单的东西。

我不认为编译器根据变量顺序分配堆栈,如果启用了优化,编译器可能会抛出变量“i”,因此请注意,“AAAAA”实际上是6个字符,您应该在结尾处计算“\0”它的未定义行为。如果您想知道使用调试器逐步检查汇编代码会发生什么情况。@MichaelWalz我已经做了大量的工作,但我认为在这篇文章中有一堆汇编代码是没有帮助的。在这两种情况下,堆栈上局部变量的汇编指令和位置彼此相对而言是相同的,这让我感到困惑。我想知道这是否是GCC正在做的事情?有趣!我想这和GCC有关。我能够复制与您上面发布的结果相同的结果。谢谢你对此事的深入调查。
$ gcc so.c -S -masm=intel

$ gcc so2.c -S -masm=intel

$ diff so.s so2.s
1c1
<       .file   "so.c"
---
>       .file   "so2.c"

$
$ clang -S -mllvm --x86-asm-syntax=intel so.c
so.c:4:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main(int arg, char* argv[])
^
so.c:4:1: note: change return type to 'int'
void main(int arg, char* argv[])
^~~~
int
1 warning generated.

$ clang -S -mllvm --x86-asm-syntax=intel so2.c
so2.c:4:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main(int arg, char* argv[])
^
so2.c:4:1: note: change return type to 'int'
void main(int arg, char* argv[])
^~~~
int
1 warning generated.

$ diff so.s so2.s
26c26
<       lea     rax, qword ptr [rbp - 24]
---
>       lea     rax, qword ptr [rbp - 20]
29c29
<       mov     dword ptr [rbp - 20], 0
---
>       mov     dword ptr [rbp - 24], 0
34c34
<       cmp     dword ptr [rbp - 20], 0
---
>       cmp     dword ptr [rbp - 24], 0

$