【问题标题】:execve won't run executable assembly fileexecve 不会运行可执行程序集文件
【发布时间】:2013-09-07 21:00:21
【问题描述】:

我正在尝试创建一个 c 程序,它接受一个可执行文件及其参数并使用 execve 运行它们,然后执行一些其他无关紧要的事情。我遇到的问题是 execve 在可执行程序集文件上调用它时不起作用。我认为问题出在我的路径上,因为我可以让 unix shell 命令正常工作,但是我无法在当前目录中获取可执行文件(使用 ./spy ./executableName,其中 spy 是我的 c 程序的名称)运行.代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/user.h>
#include <sys/reg.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

extern char **environ;

int main(int argc, char* const argv[]) {
    pid_t pid;
    char filename[50];
    char* arglist[argc];
    int i = 1,count = 0;
    int status;

    strcpy(filename, "/bin/");
    strcat(filename,argv[1]);
    for(i = 1; i< argc; i++)
        arglist[i-1] = argv[i];
    arglist[argc-1] = 0;
    arglist[0] = filename;
    if (argc == 1) {
        fprintf(stderr,"usage : %s <prog> ...\n",argv[0]);
        return -1;
    }
    pid = fork();
    if(pid == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        if(execve(filename, arglist, 0) < 0)
            fprintf(stdout,"Invalid file.");
    }
    else {
        while(1) {
            waitpid(pid,&status,0);
            if (WIFEXITED(status))
                break;
            ptrace(PTRACE_SINGLESTEP, pid,NULL, NULL);
            count++;
        }
    }
    return 0;
}

【问题讨论】:

  • 欢迎来到 Stack Overflow。请尽快阅读About 页面。你可以从 shell 运行可执行程序集文件吗?如果不是,则问题出在可执行程序集文件中。如果是这样,您还应该能够从您的代码中执行它。你可以从你的程序运行其他程序(例如ls)吗?归根结底,每个程序(shell,ls,你的名字)都是由汇编代码生成的。
  • 从您发布的来源看来,您似乎总是在作为参数传递的名称前面加上/bin/。因此,如果文件不在/bin/ 中,则无法找到,也无法运行。
  • 感谢您的欢迎!我已经能够运行可执行程序集文件,并且可以从我的程序中运行 ls 和其他程序,例如 cd 和 grep。我认为问题完全在于我的文件路径或环境变量,但我已经把头撞在墙上一段时间了,无法弄清楚。还有@alk,我试过不用/bin/作为前缀。当我这样做时,两个文件都不会运行。我知道这不是正确的方法,但我只是对如何使用 execve 处理文件系统中的程序位置感到困惑。你觉得我应该怎么做?

标签: c exec execve


【解决方案1】:

从您发布的来源看来,您似乎总是在作为参数传递的名称前面加上/bin/。因此,如果文件不在/bin/ 中,则无法找到,也无法运行。

只需更改这两行:

strcpy(filename, "/bin/");
strcat(filename,argv[1]);

成为:

strcpy(filename,argv[1]);

注意,应用此修改后,需要指定要运行的程序的完整路径。

所以要运行ls,您需要将/bin/ls 指定为程序的参数。


其他一些cmets:

因此避免因长路径/文件名更改而导致缓冲区溢出:

char filename[50];

成为:

char filename[PATH_MAX];

要获取有关 execve() 更改可能失败的原因的更多详细信息:

if(execve(filename, arglist, 0) < 0)
  fprintf(stdout,"Invalid file.");

成为:

if(execve(filename, arglist, (char*) 0) < 0)
  perror("execve() failed");

要检测可能的分叉失败,请进行更改:

pid = fork();

变成:

if (-1 == (pid = fork())) then
{
  perror("fork() failed");
}
else

【讨论】:

  • 我进行了您列出的所有更改(PATHMAX 除外,我应该导入什么来获取该变量),但仍然失败。这类似于我的早期版本,但我喜欢更具描述性的错误消息。我现在从 perror("execve() failed"); 得到一个错误。表示 execve() failed: No such file or directory 的行。此外,我的代码现在(预期)在 ls、cd 和 grep 上失败了。我没有在 /bin/ 前缀中硬编码,所以这是有道理的。
  • @user2756569:抱歉,打错了,是PATH_MAX。您需要指定要运行的程序包括它们的路径。请参阅我的回答中的注释
猜你喜欢
  • 1970-01-01
  • 2019-06-02
  • 1970-01-01
  • 2015-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 2013-08-27
相关资源
最近更新 更多