我想跳过库的初始化部分中的命令参数。库的初始化部分是:
static void pa_init_services (void) __attribute__((constructor (102)));
static void pa_init_services()
IE,它在程序内的 main() 调用之前执行。我想实现我所说的“撕掉”参数,也就是说我想查看参数的前面,检查参数是否属于我的库,然后仅为我的库解析这些选项,然后删除在 main() 获取它们之前从列表中取出它们。我不控制哪个程序包含 main(),这是用于链接到客户端程序的通用库。
例如,如果我实际上可以访问 argv POINTER 和实际的 argc 位置,那么我可以简单地执行解析和跳过过程。
GTK 文档中提到(例如)此过程,GTK 解析特定于它的选项,并在客户端程序获取它们之前跳过它们。
答案1
在 Linux[1] 上,您可以覆盖库中的__libc_start_main()
函数(调用该函数的包装器)。main()
您可以多次这样做。
例子:
#define _GNU_SOURCE /* for RTLD_NEXT */
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>
#ifdef __UCLIBC__
#define __libc_start_main __uClibc_main
#endif
#define STR_(s) #s
#define STR(s) STR_(s)
int __libc_start_main(
int (*main)(int,char**,char**), int ac, char **av,
int (*init)(int,char**,char**), void (*fini)(void),
void (*rtld_fini)(void), void *stack_end)
{
typeof(__libc_start_main) *real_lsm;
if(*(void**)&real_lsm = dlsym(RTLD_NEXT, STR(__libc_start_main)))
return real_lsm(main, ac - 1, av + 1, init, fini, rtld_fini, stack_end);
else
errx(1, "BUG: dlsym: %s", dlerror());
}
$ cc -fPIC -shared -Wall -W -Wno-parentheses skip.c -o skip1.so -ldl
$ cc -fPIC -shared -Wall -W -Wno-parentheses skip.c -o skip2.so -ldl
$ LD_PRELOAD="./skip1.so ./skip2.so" /bin/echo a b c d
c d
如果您显式地将程序链接到skip1.so
等库,这也适用。您甚至可以execve()
使用完全不同的参数来创建一个完全不同的程序。
[1] 这也适用于musl
,尽管它__libc_start_main
不需要参数rtld_fini
。在 uclibc 中,等效函数是__uClibc_main
.
答案2
可能已经找到了我自己的答案:
https://stackoverflow.com/questions/36998143/alternative-way-to-obtain-argc-and-argv-of-a-process
__attribute__((constructor)) void stuff(int argc, char **argv)
{
for (int i=0; i<argc; i++) {
printf("%s: argv[%d] = '%s'\n", __FUNCTION__, i, argv[i]);
}
}
当然,问题仍然是跳过参数,即,您可以查看参数,但是当 main() 程序发现您的 lib 参数与它自己的参数混合时,它将会失败。