我正在阅读一本书并尝试运行此示例,但我收到了分段错误 - 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下载。我想一些关于使用此代码的上下文是必要的,以避免下面的一些负面评论,抱歉留下详细信息,并感谢您的帮助。
答案 0 :(得分:11)
这显然不是一本很好的书。问题是argv
和envp
都没有初始化,因此当您写入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);
}
此替代方法在堆栈上初始化argv
和envp
,并有足够的空间分别包含两个指针和一个指针。
在上面的代码中,我做了一个额外的修改来修复另一个常见的(但在这种情况下,无害)误解。位于\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)
你永远不会分配用于argv
和envp
的“指针数组”!什么书,省略了这些关键步骤?!
在开始分配给argv = malloc(2 * sizeof(char*))
和好友之前,或者更改envp
和argv[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!");
最终的内存映射来:(圆圈中的地址,块中的内容)
答案 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]);
}