我的代码如下:preload.c,内容如下:
#include <stdio.h>
#include <stdlib.h>
int __attribute__((constructor)) main_init(void)
{
printf("Unsetting LD_PRELOAD: %x\n",unsetenv("LD_PRELOAD"));
FILE *fp = popen("ls", "r");
pclose(fp);
}
然后在 shell 中(小心执行第二个命令!):
gcc preload.c -shared -Wl,-soname,mylib -o mylib.so -fPIC
LD_PRELOAD=./mylib.so bash
!!!请小心最后一条命令,这将导致派生“sh -c ls”的无限循环。 2秒钟后用^ C(或更好的^ Z,然后查看ps)将其停止。
更多信息
LD_DEBUG=all LD_DEBUG_OUTPUT=/tmp/ld-debug LD_PRELOAD=./mylib.so bash
而不是最后一个命令,您将获得许多名为/tmp/ld-debug.*的ld-debug文件。每个 fork 过程一个。在所有这些文件中,您都会看到首先在mylib.so中搜索了符号,即使从环境中删除了LD_PRELOAD。
最佳答案
编辑:,所以问题/问题实际上是:您怎么无法使用LD_PRELOAD
中预先加载的main_init()
可靠地取消设置bash
。
原因是execve
(在您popen
之后调用)从(可能的)环境中获取了环境
extern char **environ;
这是指向您的环境的一些全局状态变量。
unsetenv()
通常会修改您的环境,因此会影响**environ
的内容。如果
bash
试图对环境做一些特别的事情(好吧……会成为shell吗?),那么您可能会遇到麻烦。显然,
bash
甚至在unsetenv()
之前就重载了main_init()
。将示例代码更改为:extern char**environ;
int __attribute__((constructor)) main_init(void)
{
int i;
printf("Unsetting LD_PRELOAD: %x\n",unsetenv("LD_PRELOAD"));
printf("LD_PRELOAD: \"%s\"\n",getenv("LD_PRELOAD"));
printf("Environ: %lx\n",environ);
printf("unsetenv: %lx\n",unsetenv);
for (i=0;environ[i];i++ ) printf("env: %s\n",environ[i]);
fflush(stdout);
FILE *fp = popen("ls", "r");
pclose(fp);
}
显示问题。在正常运行中(运行
cat
,ls
等),我得到此版本的unsetenv:unsetenv: 7f4c78fd5290
unsetenv: 7f1127317290
unsetenv: 7f1ab63a2290
但是,运行
bash
或sh
:unsetenv: 46d170
所以你有它。
bash
让你上当了;-)因此,只需使用自己的
unsetenv
修改环境,对**environ
进行操作即可:for (i=0;environ[i];i++ )
{
if ( strstr(environ[i],"LD_PRELOAD=") )
{
printf("hacking out LD_PRELOAD from environ[%d]\n",i);
environ[i][0] = 'D';
}
}
可以在
strace
中看到它:execve("/bin/sh", ["sh", "-c", "ls"], [... "DD_PRELOAD=mylib.so" ...]) = 0
Q.E.D.
关于c - 即使在unsetenv ("LD_PRELOAD"之后,LD_PRELOAD也会影响新的 child ),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3275015/