#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”.用^ C后2秒钟停止它(或者更好^ Z然后看ps).
更多信息
>这个问题在某种程度上与bash有关;或者作为用户运行的命令,或者作为popen执行的bash.
>其他关键因素:1)从预加载的库中执行popen,2)可能需要在库的初始化部分中执行popen.
>如果您使用:
LD_DEBUG=all LD_DEBUG_OUTPUT=/tmp/ld-debug LD_PRELOAD=./mylib.so bash
而不是最后一个命令,您将获得许多ld-debug文件,名为/tmp/ld-debug.*.每个分叉进程一个.在所有这些文件中,您将看到首先在mylib中搜索符号.即使LD_PRELOAD已从环境中删除.
原因是你在popen之后调用的execve从(可能)获取环境
extern char **environ;
这是一个指向您的环境的全局状态变量. unsetenv()通常会修改您的环境,因此会影响** environ的内容.
如果bash试图对环境做一些特别的事情(好吧……它会成为一个shell吗?)那么你可能会遇到麻烦.
显然,bash甚至在main_init()之前就会重载unsetenv().将示例代码更改为:
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修改环境,就像**环境一样:
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
证明完毕
原文地址:https://www.jb51.cc/bash/387140.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。