是什么导致了这种分段错误?书中的例子

时间:2010-09-20 17:00:09

标签: c

我正在阅读一本书并尝试运行此示例,但我收到了分段错误 - gdb说它是设置argv [0] = filename;

此代码直接从图书的可下载代码示例中复制/粘贴。

#include <unistd.h>

int main() {
  char filename[] = "/bin/sh\x00";
  char **argv, **envp; // arrays that contain char pointers

  argv[0] = filename; // only argument is filename - segmentation fault here
  argv[1] = 0;  // null terminate the argument array

  envp[0] = 0; // null terminate the environment array

  execve(filename, argv, envp);
}

编辑:这本书是黑客:Jon Erickson的剥削艺术,它有很好的评论。此特定示例用作将shell转换为shellcode部分中的机器代码的第一个教程,特别是它是exec_shell.c,可以从http://nostarch.com/hacking2/htm下载。我想一些关于使用此代码的上下文是必要的,以避免下面的一些负面评论,抱歉留下详细信息,并感谢您的帮助。

7 个答案:

答案 0 :(得分:11)

这显然不是一本很好的书。问题是argvenvp都没有初始化,因此当您写入argv[0]时,您试图覆盖内存中的某个随机位置。

尝试这样的事情:

#include <unistd.h>

int main() {
  char *filename = "/bin/sh";
  char *argv[2], *envp[1];

  argv[0] = filename;
  argv[1] = 0;

  envp[0] = 0;

  execve(filename, argv, envp);
}

此替代方法在堆栈上初始化argvenvp,并有足够的空间分别包含两个指针和一个指针。

在上面的代码中,我做了一个额外的修改来修复另一个常见的(但在这种情况下,无害)误解。位于\x00末尾的"/bin/sh\x00"是多余的,因为在C中,静态字符串是隐式空终止的。 "/bin/sh\x00"是由两个空值终止的字符串。

或者,正如caf所指出的,这是一个更紧凑的例子,具有完全相同的含义:

#include <unistd.h>

int main() {
  char *filename = "/bin/sh";
  char *argv[2] = { filename, 0 };
  char *envp[1] = { 0 };

  execve(filename, argv, envp);
}

答案 1 :(得分:3)

你永远不会分配用于argvenvp的“指针数组”!什么书,省略了这些关键步骤?!

在开始分配给argv = malloc(2 * sizeof(char*))和好友之前,或者更改envpargv[0]之前,可以添加argv(同样适用于envp)声明是指针数组而不是指针指针(后者是一种非常可行的方法,在这种特殊情况下,因为你确实知道在编写代码时每个指针需要多少指针 - 动态分配是因此有点过分; - )。

答案 2 :(得分:0)

char **argv

argv指向您不允许访问/写入的内存位置。这是一个更为人所知的wild pointer.

答案 3 :(得分:0)

看起来你需要一本更好的书!在这段代码中,argv是一个没有分配存储空间并指向随机存储器(或可能是NULL)的指针。当您使用argv[0] = ...取消引用它时,您的代码最终会尝试写入随机内存。你的变量声明应该更像是:

char *argv[3], *envp[1];

答案 4 :(得分:0)

我不知道你从哪里得到这本书,但它显然很糟糕。 argv是一个未初始化的指针,它包含一个随机地址。因此,访问它很可能会导致访问冲突。

答案 5 :(得分:0)

在使用这样的多级指针之前,我建议在C中阅读动态内存分配。

每当使用指针时,您还必须考虑是否需要为指针指向的数据分配空间(对于多级指针,也需要为指针本身分配空间)。

例如,

char **bar; 

这里,bar为1指针指向空间,即。足够的空间来存储一个地址。没有任何额外的数据分配,这不是很有用。

实际上,你应该这样做:

char **bar = calloc( 2 , sizeof(char *) );

这里,bar为1指针指向空间,即。再一次,空间用于存储一个地址作为条形,以及2个连续位置用于存储另外两个指针,即bar [0]&amp;酒吧1

char bar[0]= calloc( 10 , sizeof(char) );

这里,bar [0]分配空间用于存储大小为10 - 1的字符串(对于\ 0结尾)。

现在,如果你做一个字符串副本:

strcpy(bar[0],"Hello!");

最终的内存映射来:(圆圈中的地址,块中的内容) alt text

答案 6 :(得分:-1)

这里的许多人都走在正确的轨道上,但在这里遗漏了一些问题。

#include <unistd.h>

int main() {
  char filename[] = "/bin/sh\x00";
  char **argv, **envp; // arrays that contain char pointers

  argv[0] = filename; // only argument is filename - segmentation fault here
  argv[1] = 0;  // null terminate the argument array

  envp[0] = 0; // null terminate the environment array

  execve(filename, argv, envp);
}

这里的问题是:
1。字符串的指针数组永远不会被初始化。指针也占用空间,因此指针数组需要在c中使用malloc 2。指针数组中的每个字符指针在使用前都需要自己的malloc语句。

这是工作代码,打印输出显示正在发生的事情:

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

int main() {
  unsigned int i=0;
  char filename[] = "/bin/sh\x00";
  char **argv; // arrays that contain char pointers

  argv=(char **)malloc(sizeof(char*));
  argv[0]=(char *)malloc(strlen(filename)*sizeof(char));
  strcpy(argv[0],filename);

  printf("Arg 0 is %u chars long...\n",strlen(argv[0]));
  printf("Arg 0 is ");
  while (argv[0][i] != '\0') {
    printf("%c",argv[0][i]);
    i++;
  }
  printf("!\n");

  free(argv[0]);
}