尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Linux 系统中LD_PRELOAD有哪些用处?

Linux 系统中LD_PRELOAD有哪些用处?
📅 发布时间:2026/6/29 6:57:34

在 Linux 系统中,LD_PRELOAD是动态链接技术中提供的一个强大的扩展功能,允许在程序运行前优先加载指定的动态链接库,从而改变程序的行为,而无需修改程序源代码。

在实际的工作中,LD_PRELOAD的使用场景是非常多的,比如替换 linux 的内存分配器、故障注入、安全审计等。这篇文章我们来详细看看LD_PRELOAD的原理和使用方法。

LD_PRELOAD的工作原理

LD_PRELOAD 是一个环境变量,通过 LD_PRELOAD 这个环境变量指定的共享库可以覆盖其他库中的同名符号。利用这一特性,我们可以拦截某些库函数的调用,修改其行为,或者在调用前后插入一些代码。

我们接下来通过 LD_PRELOAD 实现在 open 函数的前后都注入一行打印。在这之前,我们需要介绍一些前置的知识。

dlsym 函数

dlsym 的作用是在一个已经打开的动态链接库中查找符号(函数或变量)的地址,定义如下:

void *dlsym(void *handle, const char *symbol);

其中 handle 是动态链接库句柄,symbol是要查找的符号名(函数或变量)。比如查找 printf 函数:

dlsym(RTLD_NEXT, "printf");

RTLD_NEXT 是一个特殊的标记,使用RTLD_NEXT时 dlsym 会从当前共享对象之后的下一个共享对象中查找 printf 函数的地址。

如果要能彻底理解 RTLD_NEXT,需要弄清楚动态链接库的加载顺序和内存映射,应该大部分同学接触不到,我这里先不展开。

先来看一下open函数的原始定义:

#include <fcntl.h> int open(const char *pathname, int flags, ... /* mode_t mode */ );

为了实现 open 函数的 hook,我们需要定义一个 open 函数的函数指针定义 orig_open ,用来接受 dlsym 函数的返回值。

int (*orig_open)(const char *, int, ...);

完整的代码如下:

#define _GNU_SOURCE #include <stdio.h> #include <dlfcn.h> #include <fcntl.h> int (*orig_open)(const char *, int, ...); int open(const char *filename, int flags, ...) { orig_open = dlsym(RTLD_NEXT, "open"); int mode = 0; // todo: get mode from varargs int result = orig_open(filename, flags, mode); fprintf(stderr, "[audit] open %s, fd: %d\n", filename, result); return result; }

把这个文件编译为open_hook.so文件:

gcc -shared -fPIC -o open_hook.so open_hook.c -ldl

用 LD_PRELOAD 加载,就可以拦截目标进程的文件访问,输出审计日志:

» LD_PRELOAD=./open_hook.so cat /etc/hosts [audit] open /etc/hosts, fd: 3 127.0.0.1 localhost.localdomain localhost ::1 localhost6.localdomain6 localhost6 ...

通过 LD_PRELOAD 审计,我们就可以记录 cat 命令读取和输出 /etc/passwd 文件的过程。

使用 LD_PRELOAD 做故障注入

我们可以修改内存分配函数的行为、模拟内存不足等异常情况,测试程序的健壮性。下面这段代码随机让 malloc 函数返回 ENOMEM 错误,看上层应用是否可以正确处理。

#define _GNU_SOURCE #include <dlfcn.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> void *(*orig_malloc)(size_t); void *malloc(size_t size) { orig_malloc = dlsym(RTLD_NEXT, "malloc"); if (rand() % 3 == 0) { fprintf(stderr, "[fault] malloc(%ld) = NULL\n", size); errno = ENOMEM; return NULL; } void* result = orig_malloc(size); fprintf(stderr, "[audit] malloc(%ld) = %p\n", size, result); return result; }

此时我们执行LD_PRELOAD=./malloc_hook.so ps -ef会发现 ps 命令没有很好地处理 malloc 返回异常的情况,直接 panic 了。

而有些命令则很好的处理了,比如LD_PRELOAD=./malloc_hook.so ls命令。

使用 ld_preload 来做内存分析

默认的 Linux 内存分配器 ptmalloc 在性能和内存碎片方面表现不是很好,另外 profile 的功能很弱,可以尝试替换默认的内存分配器为 jemalloc 或者 tcmalloc。它们的原理都是 hook 系统 malloc、free 等内存申请释放函数的实现,增加 profile 的逻辑。

从源码编译 tcmalloc(github.com/gperftools/…) LD_PRELOAD 来 hook 内存分配释放的函数:

HEAPPROFILE=./heap.log HEAP_PROFILE_ALLOCATION_INTERVAL=104857600 LD_PRELOAD=./libtcmalloc_and_profiler.so java -jar xxx ..

启动过程中就会看到生成了很多内存 dump 的分析文件,接下来使用 pprof 将 heap 文件转为可读性比较好的 pdf 文件。内存申请的链路如下图所示:

通过这里可以看到绝大部分的内存申请都耗在了 Java_java_util_zip_Inflater_inflateBytes,接下来就可以进一步分析。

小结

有了 LD_PRELOAD 的能力,可以在不修改源码的情况下 hack 很多应用程序的功能,不过它也有一些限制:

  • 不适用静态链接的程序。
  • 要千万小心避免递归调用,比如在自定义的 malloc 函数中调用 printf 可能会再次调用 malloc,导致无限递归。可以使用 sprintf 而不是 printf 来避免这种情况。

相关新闻

  • ReBalance:无需重训练即可实现推理精度+10%、长度-35%的动态思考调控
  • 嵌入式定时器实战:RL78 MCU脉冲测量与PWM输出API详解
  • 第8章:Agent 模式入门——让 AI 学会调用工具

最新新闻

  • Baseline模型:机器学习建模不可跳过的首行代码与问题校准器
  • 3步解决容器镜像下载难题:DaoCloud镜像加速实战指南
  • AP-14 DDSI-RTPS协议深度解析 - 发现机制、可靠传输与线协议报文结构的硬核拆解
  • API签名机制逆向实战:以酷狗音乐为例解析加密算法与实现
  • Atmosphère:为任天堂Switch打造的多层定制化固件系统
  • Windows右键菜单终极管理指南:3步打造高效工作流

日新闻

  • ENVI5.3.1实战:基于Landsat 8影像的区域无缝镶嵌与精准裁剪
  • 3步完成HS2-HF Patch安装:新手快速打造完美HoneySelect2体验
  • 微信好友检测终极指南:3分钟发现谁已悄悄删除你

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号