必须显式跟踪 open,openat,openat2,stat,fstatat,access 才能完整捕获动态库加载行为,因链接器主要使用 openat+stat 探路而非 open;漏掉任一系统调用可能导致关键路径隐身。

只用 strace -e trace=open,openat 会漏掉关键库加载行为
动态链接器(/lib64/ld-linux-x86-64.so.2 或类似)在加载共享库时,**不总是走 open(),而是大量使用 openat(AT_FDCWD, "...", O_RDONLY|O_CLOEXEC) 和 stat() 探路**。只加 -e trace=open 会错过绝大多数真实加载动作,尤其在 glibc 2.34+ 和容器环境中。
必须显式包含:-e trace=open,openat,openat2,stat,fstatat,access。其中 access() 常被用于预检权限,fstatat() 用于确认 ELF 文件类型,漏掉任何一个都可能让关键路径“隐身”。
-
openat2()是较新内核(5.6+)启用的更安全打开接口,很多新版程序(如 systemd、curl)已默认切换 -
stat()和fstatat()出现在真正openat之前——程序先判断/usr/lib/mylib.so是否存在、是否可读,再决定是否加载 - 若目标进程启动快、库多,建议加
-s 256防止路径被截成/usr/lib/libxxx.so...,无法识别真实库名
重点监控 /etc/ld.so.preload 和 LD_PRELOAD 注入点
非法库加载最常见于劫持入口:不是程序自己找库,而是被外力强制塞进一个不该出现的 .so。strace 能直接暴露这类行为——只要它触发了文件系统调用。
运行时注入必然伴随对以下路径的访问:
-
open("/etc/ld.so.preload", O_RDONLY|O_CLOEXEC)—— 全局预加载配置,root 权限下被篡改即高危 -
openat(AT_FDCWD, "/tmp/malware.so", ...)或openat(AT_FDCWD, "./injector.so", ...)——LD_PRELOAD指向的非常规路径 -
openat(AT_FDCWD, "/proc/self/exe", ...)后紧跟read()—— 某些 rootkit 会读取自身二进制以 patch 动态链接段
执行命令示例:strace -e trace=open,openat,stat,access -f -s 256 -o preload_trace.log ./vulnerable_app,然后 grep -E "(ld\.so\.preload|\.so$|\/tmp\/|\.\/)" preload_trace.log 快速定位可疑路径。
ldd 看到的路径 ≠ 运行时实际加载路径
ldd ./app 只模拟链接器搜索逻辑,不反映真实环境变量、/etc/ld.so.cache 状态或运行时 LD_LIBRARY_PATH 的覆盖效果。一个 ldd 显示 “not found” 的库,可能在 strace 中高频出现 stat("/opt/bad/libfoo.so", ...) + openat(..., O_RDONLY) 成功,说明攻击者已通过环境变量绕过默认搜索路径。
Linux AI 服务器 — 将 Linux 服务器转换为本地 AI 推理集群。使用 systemd、NVIDIA CUDA 实现无头 Linux AI,零 GUI 开销。
所以必须结合上下文判断:
- 检查 strace 输出中
openat的第一个参数:若为AT_FDCWD,看第二参数是否含LD_LIBRARY_PATH中的目录(如/malware/libs/) - 若出现
openat(3, "libcrypto.so.1.1", ...)(fd=3 是某目录),说明程序正从chdir()切换后的路径加载——这是典型的隐蔽加载手法 - 注意
openat返回值:成功返回非负 fd(如= 4),失败是= -1 ENOENT或= -1 EACCES;后者若频繁出现在敏感路径(如/root/.ssh/下搜.so),可能是探测行为
容易忽略的间接加载:dlopen() 调用不会直接显示库名
程序若用 dlopen("libevil.so", RTLD_LAZY) 动态加载,strace 默认只记录 openat(AT_FDCWD, "libevil.so", ...),但**不会告诉你这个 openat 是由 dlopen 触发,还是普通文件读取**。你只能靠调用序列和路径特征推断。
关键线索有三:
- 紧接在
mmap()或mmap2()调用之前——dlopen加载后必然映射代码段 - 路径不含标准前缀(如
/usr/lib/、/lib64/),而是/dev/shm/、/tmp/、/var/tmp/或用户家目录下的.so - 同一进程短时间内连续
openat多个.so,且无对应ldd依赖关系(比如主程序根本没声明依赖libhook.so)
此时加 -k(显示调用栈)能帮助确认:strace -k -e trace=openat,mmap2 -f ./app。若看到 openat(..., "bad.so") 的栈里有 __libc_dlopen_mode 或 dlopen,基本可判定为运行时注入。
真正的难点不在捕获,而在区分:一次 openat("/tmp/loader.so") 可能是调试工具主动加载,也可能是恶意持久化。得看它是否伴随 write 到 /proc/self/maps、是否 fork 出隐藏子进程、是否修改了 LD_PRELOAD 环境变量本身——这些细节 strace 都能给,但需要你一条一条比对。

















