【问题标题】:Howto capture posix_spawnp() with LD_PRELOAD?如何使用 LD_PRELOAD 捕获 posix_spawnp()?
【发布时间】:2018-08-21 16:29:26
【问题描述】:

我能够捕获所有低级函数,例如 open()、fopen() 等,并使用 dlsym(RTLD_NEXT, “...”) 调用原始函数,但我无法对 posix_spawnp 执行相同操作() 因为我的可执行文件崩溃了。为什么会这样以及如何捕获此功能?

抱歉耽搁了。这是我在一些运行 Linux 的嵌入式设备上尝试的代码:

int posix_spawnp(pid_t * pid, const char * file, const posix_spawn_file_actions_t * file_actions, const posix_spawnattr_t * attrp, char * const argv[], char * const envp[])
{
    orig_fopen_t orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen");
    FILE * fp = orig_fopen("/tmp/DiagnosticsAgent.log", "a");
    fprintf(fp, "*** posix_spawnp(..., {");
    int i;
    for (i = 0; argv[i] != 0; ++ i)
        fprintf(fp, "%s, ", argv[i]);
    fprintf(fp, "}, ...)\n");
    fclose(fp);

    void * handle = dlopen("libpthread.so.0", RTLD_LAZY);
    orig_posix_spawnp_t orig_posix_spawnp = (orig_posix_spawnp_t)dlsym(handle, "posix_spawnp");
    return orig_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
}

【问题讨论】:

标签: ld-preload


【解决方案1】:

适用于我的 linux/glibc。这是一个工作示例:

#!/bin/sh -eu

cat > main.c <<EOF
#include <spawn.h>
#include <sys/wait.h>
int main(int C, char **V)
{
    pid_t pid;
    if(0!=posix_spawnp(&pid,V[1],NULL,NULL,V+1,NULL))
        return 1;
    wait(0);
}
EOF
gcc main.c

cat > libspawn.c <<EOF
#define _GNU_SOURCE
#include <spawn.h>
#include <dlfcn.h>
#include <stdio.h>
typedef int spawnp_signature(pid_t *pid, const char *file,
                   const posix_spawn_file_actions_t *file_actions,
                   const posix_spawnattr_t *attrp,
                   char *const argv[], char *const envp[]);
spawnp_signature posix_spwanp;
int posix_spawnp(pid_t *pid, const char *file,
                   const posix_spawn_file_actions_t *file_actions,
                   const posix_spawnattr_t *attrp,
                   char *const argv[], char *const envp[])

{
    fprintf(stderr, "OVERRIDE\n");
    spawnp_signature *real = dlsym(RTLD_NEXT,__func__);
    return real(pid,file,file_actions,attrp,argv,envp);

}
EOF
gcc -shared -fpic -o libspawn.so libspawn.c -ldl

./a.out echo hello world
LD_PRELOAD=$PWD/libspawn.so ./a.out echo hello world

第二个输出按预期打印了单词OVERRIDE

编辑: 在使您的示例可编译后,它也适用于我。可能某些未经检查的调用在您的计算机上失败,或者您忘记链接 dl 库。

#!/bin/sh -eu

cat > main.c <<EOF
#include <spawn.h>
#include <sys/wait.h>
int main(int C, char **V)
{
    pid_t pid;
    if(0!=posix_spawnp(&pid,V[1],NULL,NULL,V+1,NULL))
        return 1;
    wait(0);
}
EOF
gcc main.c

cat > libspawn.c <<EOF
#define _GNU_SOURCE
#include <spawn.h>
#include <dlfcn.h>
#include <stdio.h>
typedef int spawnp_signature(pid_t *pid, const char *file,
                   const posix_spawn_file_actions_t *file_actions,
                   const posix_spawnattr_t *attrp,
                   char *const argv[], char *const envp[]);
spawnp_signature posix_spwanp;
int posix_spawnp(pid_t *pid, const char *file,
                   const posix_spawn_file_actions_t *file_actions,
                   const posix_spawnattr_t *attrp,
                   char *const argv[], char *const envp[])

{
    fprintf(stderr, "OVERRIDE\n");
    spawnp_signature *real = dlsym(RTLD_NEXT,__func__);
    return real(pid,file,file_actions,attrp,argv,envp);

}
EOF
cat >libspawn.c <<EOF
#define _GNU_SOURCE
#include <spawn.h>
#include <dlfcn.h>
#include <stdio.h>
typedef int (*orig_posix_spawnp_t)(pid_t *pid, const char *file,
                   const posix_spawn_file_actions_t *file_actions,
                   const posix_spawnattr_t *attrp,
                   char *const argv[], char *const envp[]);
typedef FILE *(*orig_fopen_t)(char const*, char const*);
int posix_spawnp(pid_t * pid, const char * file, const posix_spawn_file_actions_t * file_actions, const posix_spawnattr_t * attrp, char * const argv[], char * const envp[])
{
    orig_fopen_t orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen");
    FILE * fp = orig_fopen("/tmp/DiagnosticsAgent.log", "a");
    fprintf(fp, "*** posix_spawnp(..., {");
    int i;
    for (i = 0; argv[i] != 0; ++ i)
        fprintf(fp, "%s, ", argv[i]);
    fprintf(fp, "}, ...)\n");
    fclose(fp);

    void * handle = dlopen("libpthread.so.0", RTLD_LAZY);
    if(!handle) { perror(0); return -1; }
    orig_posix_spawnp_t orig_posix_spawnp = (orig_posix_spawnp_t)dlsym(handle, "posix_spawnp");
    fprintf(stderr,"OVERRIDE\t");
    return orig_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
}
EOF
gcc -shared -fpic -o libspawn.so libspawn.c -ldl

./a.out echo hello world
LD_PRELOAD=$PWD/libspawn.so ./a.out echo hello world

【讨论】:

  • 好的,您的示例适用于 Linux x86,但不适用于我的 Linux armv7(段错误)。但你已经回答了我最初的问题。
  • @PhilBouchard 谢谢。也试图回答编辑。我的猜测是 dlopen 可能在那里失败(您正在硬编码特定的文件名,这可能很脆弱)。如果您还不想添加错误检查,可以检查 strace(但您也应该添加错误检查)。
  • 我确实尝试过使用传统的 dlsym(RTLD_NEXT, "...") 并且遇到了同样的崩溃问题。我使用 dlopen() 因为我认为该函数位于那里。我会进行一般搜索...
  • ... 在 Linux x86 上,posix_spawnp() 在 libc.so.6 中。在嵌入式设备上,它可能在其他地方(但我不容易找到)。
  • 你已经回答了我的问题!
猜你喜欢
  • 2011-06-09
  • 2016-06-16
  • 2022-11-11
  • 2013-03-14
  • 2012-05-13
  • 1970-01-01
  • 1970-01-01
  • 2021-05-27
相关资源
最近更新 更多