【问题标题】:C execve() parameters [spawn a shell example]C execve() 参数 [生成一个 shell 示例]
【发布时间】:2015-05-10 09:27:56
【问题描述】:

我必须填写以下参数:

int execve(const char *filename, char *const argv[], char *const envp[]);

如果我执行这个程序:

#include <unistd.h>
int main() {
        char *args[2];
        args[0] = "/bin/sh";
        args[1] = NULL;
        execve(args[0], args, NULL);
}

shell 按预期正确生成。

我的问题是,如果我像这样将 NULL 作为第二个参数传递,shell 也会正确生成:

#include <unistd.h>

int main() {
        char *args[2];
        args[0] = "/bin/sh";
        args[1] = NULL;
        execve(args[0], NULL, NULL);
}

那么使用 args 向量(带有“/bin/sh”+ NULL)作为第二个参数而不是 NULL 的目的是什么?

【问题讨论】:

  • 在这种情况下,您没有传递任何参数,因此没有区别。您可以选择在args 中传递一些参数。
  • 那么,为什么在我看到的所有示例中,人们习惯将 /bin/sh + NULL 作为 arg 传递? arg参数直接设为NULL更容易理解。
  • 可能是因为是一个例子,明白了如果我传递一些参数,必须有一个NULL作为字符串终止符?
  • 自己编写一个打印出参数的 C 程序,如果你用你的两个示例程序调用它,你应该会看到不同。

标签: c shellcode execve


【解决方案1】:

在这一行:execve(args[0], NULL, NULL); 你只是使用args 数组的第一个元素。你也可以使用char* command="/bin/sh" 之类的东西。您必须传递一些东西,因为 execve() 就是这样定义的。在您的情况下,您传递 NULL 因为您不需要传递任何东西。

execve() 的第二个参数的重点是将参数传递给您正在生成的命令。假设您只想执行ls 而不是shell,然后您可以传递f.e.这些论点:

#include <unistd.h>
int main() {
        char *args[2];
        args[0] = "/bin/ls";
        args[1] = "-lh";
        execve(args[0], args, NULL);
}

另外,引用man execve

argv 是传递给新程序的参数字符串数组。 由 约定,这些字符串中的第一个应包含文件名 与正在执行的文件相关联。 envp 是一个数组 字符串,通常采用 key=value 的形式,传递为 新程序的环境。

【讨论】:

    【解决方案2】:

    如果您将空指针作为execve 的第二个或第三个参数传递,根据POSIX,您的程序不正确;这两个参数都必须是非空的。 (这在the specification of execve 中并没有明确说明,但它就在那里。)我目前正在一个处理传递空指针的操作系统上输入这个,

    execve("executable", 0, 0);
    

    相当于传递空数组,例如

    execve("executable", (char *[]){0}, (char *[]){0});
    

    但得知其他操作系统会触发分段错误或返回 -1 并将 errno 设置为 EFAULTEINVAL 时,我不会感到惊讶。

    允许为这些参数传递空数组,但如果第二个参数是空数组,则新执行的程序将在argc/argv 中接收零参数,和/或在envp/@ 中接收零环境变量987654332@ 如果第三个参数是一个空数组。在这些情况下,许多程序会发生故障。例如,看到类似的东西是很常见的

    int main(int argc, char **argv)
    {
       if (argc != 4) {
         fprintf(stderr, "usage: %s one two three\n", argv[0]);
         return 2;
       }
       // ...
    }
    

    程序隐式假定argv[0] 将始终为非空。

    因此,您应该始终为两个参数提供 非空 数组。通常的约定是,如果您没有其他事情可做,则使用

    execve(program, (char *[]){program, 0}, environ);
    

    它提供程序自己的名称为argv[0],没有其他参数,以及您从自己的父级获得的同一组环境变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-18
      • 2023-04-03
      相关资源
      最近更新 更多