【问题标题】:segmentation fault on buffer overflow缓冲区溢出分段错误
【发布时间】:2015-11-24 18:02:17
【问题描述】:

我无法运行此 c 代码。当我这样做时,我得到分段错误和“返回”错误返回 0xdeadbeef;

大家有什么建议吗?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int lame(unsigned int size, unsigned int value){

unsigned int array1[4];
unsigned int array2[6];
array2[5] = value;
memcpy(&array1, &array2, size * sizeof(unsigned int));

return 1;
}

void awesome(){
printf("awwwwwww yeaaahhhhh! All awesome, all the time!\n");
}

main(unsigned int argc, char ** argv){
unsigned int size, value;
size = strtoul(argv[1], 0, 10);
value = strtoul(argv[2], 0, 16);

if(!lame(size, value)){
    awesome();
}
else{
    printf("I am soooo lame :(\n");
}

return 0xdeadbeef;
}

【问题讨论】:

  • 不要发布代码链接。特别是不要发布代码图像的链接。在您的帖子中发布代表代码
  • 首先,不要发布代码链接,链接可能会过时并使您的问题变得毫无价值。其次,更重要的是,不要发布文字图片!这使得我们完全不可能复制和粘贴它来自己尝试。相反,您应该复制并粘贴文本并将其作为文本放入问题正文中。
  • 几乎每一行代码都至少存在一个错误。您需要的是入门编程课程,而不是问答网站。
  • 另外,如果您遇到崩溃,那么您应该在调试器中运行以定位代码中的崩溃。此外,如果你有缓冲区溢出,那么你有未定义的行为,这是不好的,可能导致任何类型的事情发生。
  • 我现在已经复制了代码。很抱歉

标签: c return buffer warnings


【解决方案1】:

我说过“您的代码几乎每一行都至少存在一个错误”,现在我将列出它们。如果我在一行上没有任何 cmets,则该行上没有 错误,但您还需要阅读正确的代码格式和样式。

int lame(unsigned int size, unsigned int value){
unsigned int array1[4];
unsigned int array2[6];
array2[5] = value;
memcpy(&array1, &array2, size * sizeof(unsigned int));
return 1;
}

如果size 大于4,则memcpy 行上的未定义行为。由于size 是从用户输入中获取的,因此该程序包含一个缓冲区溢出漏洞,尽管该漏洞可能难以利用。 (您需要阅读“Smashing the Stack for Fun and Profit。”)

此函数没有外部可见的副作用。除了return 1 之外,编译器可能并且可能会删除其所有代码

始终返回相同常量值的函数应重构为返回void。不在当前文件外使用的函数应声明为static

void awesome(){
printf("awwwwwww yeaaahhhhh! All awesome, all the time!\n");
}

printf 的这种用法可以替换为puts。不在当前文件外使用的函数应声明为static

main(unsigned int argc, char ** argv){

main 的第一个参数必须是 int 类型,而不是 unsigned int。缺少返回类型(必须是int,而不是void);许多编译器会容忍这种情况(将其视为隐式返回int)以向后兼容 C89 之前的代码,但它仍然是错误的。

unsigned int size, value;
size = strtoul(argv[1], 0, 10);
value = strtoul(argv[2], 0, 16);

sizevalue 都应该是 unsigned long 以与 strtoul 返回的内容保持一致。

如果命令行参数少于两个,则行为未定义。

需要检查对strtoul 的两次调用是否失败。这是不平凡的;阅读EXAMPLES section of the OpenBSD manpage for strtoul 了解如何正确

但是,使用 strtoul 而不是 atoi(您无法检查失败)或 sscanf(在整数溢出时具有未定义行为)的道具。

if(!lame(size, value)){
    awesome();
}
else{
    printf("I am soooo lame :(\n");
}

编译器可以并且将确定lame 始终返回1,并优化对awesome 的调用。 (事实上​​,除了上述printf 之外,它有权优化所有内容,因为所有控制流路径要么触发未定义的行为,要么达到此printf,并且没有其他外部可见的效果。我手头的编译器并不是那么聪明,但它们确实删除了 if-then-else 和 lame 中的所有代码。)

printf 的这种用法也可以用puts 代替。

当你不再称自己是跛足的那一刻,你的跛足就会自动减少 23%。

return 0xdeadbeef;

main 返回的值是有意义的。 0 表示整个程序的成功,任何其他值都表示某种失败。除非您打算指示失败,否则始终返回 0。此外,只有 [0, 127] 范围内的值才能被父进程跨平台可靠地接收; 0xdeadbeef 马上就出来了。

在您的屏幕截图中,main 返回了 void,而不是缺少返回类型;加上带有值的return 语句应该会导致程序无法编译。不过,您的编译器可能会在 main 中容忍它。

【讨论】:

  • 非常感谢,但我仍然很困惑!你能给我一个这个工作的return 1部分的例子吗?
  • 对不起,我不明白你想要的例子。
  • 如如何修复 memcpy 行(蹩脚函数)
  • 我不能告诉你memcpy应该做什么,因为整个程序没有做任何有意义的事情,甚至没有做任何有意义的事情.但是,每次调用memcpy 时,您必须始终确保其第三个参数不能大于其第一个参数的分配大小。在这种情况下,这将转换为:size 不得超过 4。
  • 我想做的只是做一个简单的缓冲区溢出挑战,用户将不得不尝试超出缓冲区边界。我以为我在正确的轨道上?这个挑战在执行时应该打印出来我太蹩脚了:(消息。挑战是让程序打印出来 awwwwwww yeaaahhhhh!所有时间都很棒!而不是。
猜你喜欢
  • 2017-05-12
  • 1970-01-01
  • 1970-01-01
  • 2016-07-27
  • 1970-01-01
  • 1970-01-01
  • 2023-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多