堆栈上的局部变量
Local variables on stack
为了理解栈帧的概念,我自己写了一个小程序。首先,我将向您展示代码和一些草图,然后我将提出我的问题:
所以,程序:
int check_pw(char *password){
int valid = 0;
char buffer[10];
strcpy(buffer, password);
if(strcmp(buffer, "a") == 0){
valid = 1;
}
return valid;
}
int main(int argc, char *argv[]){
if(check_pw(argv[1])){
printf("OK\n");
}
else{
printf("Wrong password\n");
}
}
我将密码作为命令行参数提供。而如果等于'a',那就没问题了。所以,我觉得很清楚了。
现在草图函数 check_pw
的栈帧看起来应该是这样的:
------------------------- LOW
| buffer |
-------------------------
| valid |
-------------------------
| old EBP |
-------------------------
| RET |
-------------------------
| password |
------------------------- HIGH
现在,我的问题是:
我假设草图是正确的。那么,那么第一个局部变量 "valid" 必须比第二个变量 "buffer" 获得更高的内存地址,对吗?
但是当我使用 gdb 作为调试器时(我使用 Ubuntu Lucid Lynx),在正确的位置设置我的断点并输入以下内容:x/x &valid 和 x/x &buffer 然后我得到 "valid" 的地址 0xbffff388 和 "buffer" 的 0xbffff38c
所以,很明显"buffer"的地址高了,但是为什么呢?
为了防止缓冲区溢出(例如,可以通过使用 strcpy 来利用缓冲区溢出),有一种技术包括在堆栈上分配的所有数组的末尾写入一个预定义的值.当函数returns时,验证值(通常称为金丝雀),如果值被更改,程序将中止。
函数完成后程序必须跳回的地址被压入堆栈。一种常见的攻击是覆盖该值,使程序执行攻击者注入的代码。如果有一个 canary 被破坏的缓冲区和指针,攻击者将不得不猜测 canary 值以获得对程序执行的控制。
您可以在维基百科上了解更多信息:http://en.wikipedia.org/wiki/Buffer_overflow_protection#A_canary_example
您可以在 gcc 上禁用它。如果您像这样编译代码(假设您的程序文件名为 login.c):
gcc -g -fno-stack-protector login.c
您会注意到变量不再重新排列。
为了理解栈帧的概念,我自己写了一个小程序。首先,我将向您展示代码和一些草图,然后我将提出我的问题:
所以,程序:
int check_pw(char *password){
int valid = 0;
char buffer[10];
strcpy(buffer, password);
if(strcmp(buffer, "a") == 0){
valid = 1;
}
return valid;
}
int main(int argc, char *argv[]){
if(check_pw(argv[1])){
printf("OK\n");
}
else{
printf("Wrong password\n");
}
}
我将密码作为命令行参数提供。而如果等于'a',那就没问题了。所以,我觉得很清楚了。
现在草图函数 check_pw
的栈帧看起来应该是这样的:
------------------------- LOW
| buffer |
-------------------------
| valid |
-------------------------
| old EBP |
-------------------------
| RET |
-------------------------
| password |
------------------------- HIGH
现在,我的问题是:
我假设草图是正确的。那么,那么第一个局部变量 "valid" 必须比第二个变量 "buffer" 获得更高的内存地址,对吗?
但是当我使用 gdb 作为调试器时(我使用 Ubuntu Lucid Lynx),在正确的位置设置我的断点并输入以下内容:x/x &valid 和 x/x &buffer 然后我得到 "valid" 的地址 0xbffff388 和 "buffer" 的 0xbffff38c 所以,很明显"buffer"的地址高了,但是为什么呢?
为了防止缓冲区溢出(例如,可以通过使用 strcpy 来利用缓冲区溢出),有一种技术包括在堆栈上分配的所有数组的末尾写入一个预定义的值.当函数returns时,验证值(通常称为金丝雀),如果值被更改,程序将中止。
函数完成后程序必须跳回的地址被压入堆栈。一种常见的攻击是覆盖该值,使程序执行攻击者注入的代码。如果有一个 canary 被破坏的缓冲区和指针,攻击者将不得不猜测 canary 值以获得对程序执行的控制。
您可以在维基百科上了解更多信息:http://en.wikipedia.org/wiki/Buffer_overflow_protection#A_canary_example
您可以在 gcc 上禁用它。如果您像这样编译代码(假设您的程序文件名为 login.c):
gcc -g -fno-stack-protector login.c
您会注意到变量不再重新排列。