排查LD_PRELOAD拦截需四步:一查环境变量是否设置;二溯来源(用户/系统/容器/systemd);三析so库导出函数及依赖;四验生效性(区分setuid限制、检查/proc/pid/environ和/etc/ld.so.preload)。

排查 LD_PRELOAD 植入的系统调用拦截,关键不是“有没有设”,而是“谁设的、设给谁、设了什么、是否生效”。它不留下明显进程或文件痕迹,但会在动态链接阶段悄然介入。下面分四步直击核心。
一、确认当前环境是否存在 LD_PRELOAD 设置
这是最快速的第一筛。很多报错(如 LD_PRELOAD cannot be preloaded)就源于此变量残留:
- 运行
echo $LD_PRELOAD查看是否非空;若输出路径,记下该 .so 文件名和路径 - 检查是否被子 shell 或服务继承:在新终端中执行同一命令,对比结果
- 注意空格和引号干扰——有时变量值含多余空格或未闭合引号,也会导致加载失败但不报错
二、追溯 LD_PRELOAD 的来源位置
变量可能来自多个层级,需逐层排查:
- 用户级配置:搜索
~/.bashrc、~/.bash_profile、~/.zshrc、~/.profile中的export LD_PRELOAD=或unset LD_PRELOAD后又重新赋值的情况 - 系统级配置:检查
/etc/environment、/etc/profile、/etc/profile.d/*.sh,尤其留意由 CUDA、NVIDIA 驱动、安全审计工具或监控 agent 自动写入的脚本 - 容器与编排环境:Docker 启动时用
--env LD_PRELOAD=...;Kubernetes Pod 的env:字段或 initContainer 中可能硬编码该变量 - systemd 服务:对可疑服务运行
systemctl show --property=Environment <service></service>,查看是否注入了 LD_PRELOAD
三、分析预加载库的行为特征
即使找到 .so 文件,也不能只看文件名。要验证它是否真在拦截系统调用:
- 用
file和readelf -h确认架构匹配(如 x86_64 程序不能加载 i386 so) - 用
nm -D /path/to/libxxx.so | grep -E "(open|read|write|exec|fork|malloc)"查看是否导出常见被 hook 函数 - 用
ldd /path/to/libxxx.so看它自身是否依赖异常库(如链接了libprocesshider.so这类已知隐藏工具) - 临时启用 strace 观察:启动一个简单程序并加 LD_PRELOAD,再运行
strace -e trace=openat,open,execve -f ./your_program 2>&1 | grep -E "(open|exec)",比对函数调用前后行为变化
四、检测运行时是否实际生效
LD_PRELOAD 对 setuid 程序(如 sudo、passwd)默认无效,glibc 会主动清空该变量。因此需区分场景:
- 对普通用户程序:用
cat /proc/$(pidof your_program)/environ | tr '\0' '\n' | grep LD_PRELOAD确认进程内变量真实值 - 检查是否被绕过:运行
ls -l /usr/bin/sudo,若权限含s(如-rwsr-xr-x),说明 LD_PRELOAD 在该进程里必然失效 - 全局生效的真正后门是
/etc/ld.so.preload—— 它无需环境变量,所有动态链接程序都会加载。用lsattr /etc/ld.so.preload和stat /etc/ld.so.preload检查是否被篡改或锁定 - 若怀疑隐蔽 hook,可对比
ps aux与ls /proc/[0-9]* 2>/dev/null | cut -d'/' -f3 | sort -u的 PID 差异,缺失的 PID 可能被 LD_PRELOAD + readdir hook 隐藏


















