Buffer owerflow - 堆栈上局部变量的顺序

时间:2015-08-28 17:39:22

标签: c stack buffer-overflow local-variables

我对如何在堆栈上排序局部变量感到很困惑。据我所知,(在Intel x86上)局部变量在代码中存储时从较高地址到较低地址存储。很明显,这段代码:

int i = 0;
char buffer[4];
strcpy(buffer, "aaaaaaaaaaaaaaa");
printf("%d", i);

,产生这样的东西:

1633771873

被覆盖的缓冲区覆盖了i变量。

但是,如果我交换前两行:

char buffer[4];
int i = 0;
strcpy(buffer, "aaaaaaaaaaaaaaa");
printf("%d", i);

,输出完全相同。

怎么可能? i的地址低于buffer的地址,因此缓冲区的溢出应覆盖其他数据,但不会覆盖i。或者我错过了什么?

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

没有关于局部变量顺序的规则,因此编译器通常可以按照自己喜欢的方式自由分配它们。但另一方面,编译器将使用许多策略来减少您自愿尝试的可能性。

其中一个安全性增强是分配一个总是远离其他标量变量的缓冲区,因为一个数组可以超出边界并且更倾向于膨胀相邻变量。另一个技巧是在数组之后添加一些陷阱空空间,以便为边界问题创建一种隔离。

无论如何,您可以使用调试器查看程序集以确认变量定位。

答案 1 :(得分:0)

如果要查看编译器如何分配局部变量,请尝试使用gcc -S进行编译,这将输出汇编代码。在汇编代码中,您可以看到编译器如何选择对变量进行排序。

编译器选择如何对局部变量进行排序时要记住的一件事是每个char只需要对齐1(这意味着它可以从内存的任何字节开始),另一方面int必须对齐4(这意味着它只能从一个可被4整除的字节开始),因此根据对齐方式,编译器有自己的逻辑,如何避免使用空字节数据,这意味着它通常是组以某种顺序组合相似类型的变量。所以即使你这样定义它们:

int a;
char c;
int b;
char d;

编译器很可能将内存和字符组合在内存中,因此从顶部的低内存到底部的高内存的内存可能类似于:

 low memory
  |    |      | char d | char c|
  |           int b            |
  |           int a            |
  high memory

每个块的||表示一个字节,整行表示4个字节。

尝试使用汇编代码搞乱,有时非常有趣。