c - 如何从 ps 中隐藏 execl() 参数?

标签 c fork exec ps unistd.h

如何在 execl() 之后隐藏/更改进程参数?或者我们如何隐藏/更改使用 system()/execl() 的子进程的参数?

正在处理 SHC (此应用程序的目的是将 bash 脚本编译成二进制文件)我正在使用 execl() 函数来执行 sh 脚本;问题是 execl() 参数暴露给了 ps;这个问题的目的是让SHC更可靠一点,解决一些用户反馈的问题。

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

int main(int argc,char* argv[]){

    int runThis;

    //Create child process
    if(fork() == 0){ 
        printf("I'm the child\n");
        //runThis = system("echo test; sleep 30");
        runThis = execl("/bin/sh", "sh", "-c", "echo test; sleep 30", (char *) 0);
        exit(0);
    } else {
        printf("I'm the parent.\n");
    }

    printf("Continue main\n");

    return 0;
}

运行这段代码时,sh -c echo test; sleep 30 暴露于 ps

解决方案尝试1:成功但不可靠

ld_preload 隐藏命令参数可以用这个来完成 solution或使用 setenv("LD_PRELOAD","myLib.so",1);(dlopen() 不能与 execl() 一起使用),此解决方案确实需要将库加载到我们的应用程序。

解决方案尝试 2:半成功

ld --wrap=symbol 包装 __libc_start_main,这适用于父级,但代码不会在 execl() 之后包装/系统()

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

int __real___libc_start_main(int (*main) (int, char **, char **), int argc, char **ubp_av, void (*init) (void), void (*fini)(void), void (*rtld_fini)(void), void (*stack_end));

int __wrap___libc_start_main(int (*main) (int, char **, char **), int argc, char **ubp_av, void (*init) (void), void (*fini)(void), void (*rtld_fini)(void), void (*stack_end)) {    
    printf("Main called\n");
    //ubp_av[1] = "test";
    int result = __real___libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, stack_end);
    return result;
}

构建命令:(wrap.c是上面的代码,example.c是第一个代码示例)

gcc -c example.c -o 1.o;
gcc -c wrap.c -o 2.o;  
gcc -Wl,-wrap,__libc_start_main -Wl,-wrap=__libc_start_main 1.o 2.o -o myapp

解决方案尝试 3:半成功

类似于尝试 2,它包括在构建时链接尝试 1 的代码...但这不适用于 execl()

  • 将库构建为 libfoo 或其他名称 gcc -Wall -O2 -fpic -shared -Wl,-soname,libfoo.so -ldl -o libfoo.so wrap.c (wrap. c 是尝试 1) 的代码
  • 安装 sudo ln -s/path/libfoo.so/usr/lib64/libfoo.so
  • 链接 gcc example.c -o myapp -L.. -lfoo

解决方案尝试 4:相关但在这里没有用

可以从父进程使用 Ptrace 修改 execl() 之后的子参数 example-1 example-2

最佳答案

替代方案:

Bash 内容可以通过管道传输,从而对 ps 隐藏

script="script goes here"
echo $script | bash

缓解方案:

这不是一个完美的解决方案,但它会回答问题,这段代码会在/tmp build 下创建一个 shc_x.c,然后用环境变量预加载它。

shc_x.c,通过替换将 bash sh 内容注入(inject) ******** 参数并更改子命令参数的位置,从而将它们也从 ps 中隐藏。

shc_x.c:(此文件是用第二段代码生成的)

/*
 * Copyright 2019 - Intika <intika@librefox.org>
 * Replace ******** with secret read from fd 21
 * Also change arguments location of sub commands (sh script commands)
 * gcc -Wall -fpic -shared -o shc_secret.so shc_secret.c -ldl 
 */

#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */
#define PLACEHOLDER "********"
#include <dlfcn.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

static char secret[128000]; //max size
typedef int (*pfi)(int, char **, char **);
static pfi real_main;

// copy argv to new location
char **copyargs(int argc, char** argv){
    char **newargv = malloc((argc+1)*sizeof(*argv));
    char *from,*to;
    int i,len;

    for(i = 0; i<argc; i++){
        from = argv[i];
        len = strlen(from)+1;
        to = malloc(len);
        memcpy(to,from,len);
        // zap old argv space
        memset(from,'\0',len);      
        newargv[i] = to;
        argv[i] = 0;
    }
    newargv[argc] = 0;
    return newargv;
}

static int mymain(int argc, char** argv, char** env) {
    //fprintf(stderr, "Inject main argc = %d\n", argc);
    return real_main(argc, copyargs(argc,argv), env);
}

int __libc_start_main(int (*main) (int, char**, char**),
                      int argc,
                      char **argv,
                      void (*init) (void),
                      void (*fini)(void),
                      void (*rtld_fini)(void),
                      void (*stack_end)){
    static int (*real___libc_start_main)() = NULL;
    int n;

    if (!real___libc_start_main) {
        real___libc_start_main = dlsym(RTLD_NEXT, "__libc_start_main");
        if (!real___libc_start_main) abort();
    }

    n = read(21, secret, sizeof(secret));
    if (n > 0) {
      int i;

    if (secret[n - 1] == '\n') secret[--n] = '\0'; 
      for (i = 1; i < argc; i++)
        if (strcmp(argv[i], PLACEHOLDER) == 0)
          argv[i] = secret;
    }

    real_main = main;

    return real___libc_start_main(mymain, argc, argv, init, fini, rtld_fini, stack_end);
}

在主 c 应用程序上:

static const char * shc_x[] = {
"/*",
" * Copyright 2019 - Intika <intika@librefox.org>",
" * Replace ******** with secret read from fd 21",
" * Also change arguments location of sub commands (sh script commands)",
" * gcc -Wall -fpic -shared -o shc_secret.so shc_secret.c -ldl",
" */",
"",
"#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */",
"#define PLACEHOLDER \"********\"",
"#include <dlfcn.h>",
"#include <stdlib.h>",
"#include <string.h>",
"#include <unistd.h>",
"#include <stdio.h>",
"#include <signal.h>",
"",
"static char secret[128000]; //max size",
"typedef int (*pfi)(int, char **, char **);",
"static pfi real_main;",
"",
"// copy argv to new location",
"char **copyargs(int argc, char** argv){",
"    char **newargv = malloc((argc+1)*sizeof(*argv));",
"    char *from,*to;",
"    int i,len;",
"",
"    for(i = 0; i<argc; i++){",
"        from = argv[i];",
"        len = strlen(from)+1;",
"        to = malloc(len);",
"        memcpy(to,from,len);",
"        // zap old argv space",
"        memset(from,'\\0',len);",
"        newargv[i] = to;",
"        argv[i] = 0;",
"    }",
"    newargv[argc] = 0;",
"    return newargv;",
"}",
"",
"static int mymain(int argc, char** argv, char** env) {",
"    //fprintf(stderr, \"Inject main argc = %d\\n\", argc);",
"    return real_main(argc, copyargs(argc,argv), env);",
"}",
"",
"int __libc_start_main(int (*main) (int, char**, char**),",
"                      int argc,",
"                      char **argv,",
"                      void (*init) (void),",
"                      void (*fini)(void),",
"                      void (*rtld_fini)(void),",
"                      void (*stack_end)){",
"    static int (*real___libc_start_main)() = NULL;",
"    int n;",
"",
"    if (!real___libc_start_main) {",
"        real___libc_start_main = dlsym(RTLD_NEXT, \"__libc_start_main\");",
"        if (!real___libc_start_main) abort();",
"    }",
"",
"    n = read(21, secret, sizeof(secret));",
"    if (n > 0) {",
"      int i;",
"",
"    if (secret[n - 1] == '\\n') secret[--n] = '\\0';",
"    for (i = 1; i < argc; i++)",
"        if (strcmp(argv[i], PLACEHOLDER) == 0)",
"          argv[i] = secret;",
"    }",
"",
"    real_main = main;",
"",
"    return real___libc_start_main(mymain, argc, argv, init, fini, rtld_fini, stack_end);",
"}",
"",
0};

#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/prctl.h>
#define PR_SET_PTRACER 0x59616d61
#include <stddef.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <linux/audit.h>

void shc_x_file() {
    FILE *fp;
    int line = 0;

    if ((fp = fopen("/tmp/shc_x.c", "w")) == NULL ) {exit(1); exit(1);}
    for (line = 0; shc_x[line]; line++) fprintf(fp, "%s\n", shc_x[line]);
    fflush(fp);fclose(fp);
}

int make() {
    char * cc, * cflags, * ldflags;
    char cmd[4096];

    cc = getenv("CC");
    if (!cc) cc = "cc";

    sprintf(cmd, "%s %s -o %s %s", cc, "-Wall -fpic -shared", "/tmp/shc_x.so", "/tmp/shc_x.c -ldl");
    if (system(cmd)) {remove("/tmp/shc_x.c"); return -1;}
    remove("/tmp/shc_x.c"); return 0;
}

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

    shc_x_file();
    if (make()) {exit(1);}

    setenv("LD_PRELOAD","/tmp/shc_x.so",1);

    // rest of the code execl etc...
}

注意:参数总是可以通过多种方式恢复,这段代码只是让逆向变得更复杂一些。

关于c - 如何从 ps 中隐藏 execl() 参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54819710/

相关文章:

c - 如何 fork ()确切数量的 child

unix - 在多线程(带有 pthreads)进程中 fork() 之后,所有可重入函数都可以安全使用吗?

c - 在 fork 和 exec 之后在父子之间共享一个文件描述符

php - mysqldump 停止新的 apache 升级

c - Semget 和 fork() : no such file or directory

c - Windows 复制命令如 XCOPY、COPY、ROBOCOPY 在 System() 中的 C 语言中不起作用

时间:2019-02-08 标签:c++calllinuxcommandsforkschilds

go - 同时扫描 stdout 和 stderr

c - 释放为 C 中的字符串分配的内存

c - 我无法在 Eclipse 中运行 C 程序