当前位置: 首页 > news >正文

Linux 系统中LD_PRELOAD有哪些用处?

在 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 来避免这种情况。
http://www.jsqmd.com/news/1088086/

相关文章:

  • ZXing自动化测试终极指南:Espresso与UI Automator实战对比
  • 模型YAML配置文件指南:从结构定义到部署契约的工程实践
  • Claude Managed Agents:AI Agent 运行时的标准化时刻
  • Windows Cleaner:5分钟掌握终极Windows系统清理工具,彻底解决C盘爆红问题
  • 集成学习常见概念的优缺点总结
  • 6款实用降AI率工具 改写实力出众
  • 软考系统分析师高频考点全景图(含2024新增AI治理模块):1张思维导图覆盖全部19个命题维度,稀缺性仅开放48小时
  • 音乐平台接口逆向工程:从抓包到签名算法的VIP请求模拟实战
  • 如何快速解决Windows驱动签名问题:完整绕过指南
  • Windows系统下实现多OneDrive个人账号同步的实用技巧
  • 任意文件下载漏洞深度剖析:从原理到防御的完整攻击链拆解
  • 抖音直播数据采集终极指南:高效获取实时弹幕与用户互动信息
  • APP安全漏洞探针实战:从SAST/DAST到IAST/SCA的攻防技术解析
  • ESP32 SSD1306 OLED驱动实战:构建现代物联网显示界面的完整指南
  • 从零到精通:yt-dlp-gui的终极视频下载指南
  • Wireshark实战:抓包解析5G SUCI加密机制与隐私保护原理
  • AES-CMAC算法在汽车诊断安全访问中的应用与实现
  • AI助手安全攻防实战:从攻击面测绘到纵深防御的移动安全新挑战
  • C# Selenium自动化测试环境搭建:五大核心问题与解决方案详解
  • 免费解锁iPhone激活锁:applera1n终极绕过方案完整指南
  • 【软考退税终极指南】:2024最新政策解读+实操避坑清单(附税务局内部审核逻辑)
  • NX-CGRA架构:边缘Transformer加速的高效能效比方案
  • arXiv提交避坑指南:巧用Overleaf将PDF“伪装”为LaTeX源码
  • 高效跨平台资源下载实战:从原理到实战的完整指南
  • SVM底层逻辑:从最大间隔到软间隔的工程权衡
  • 什么是假设检验?它在数据分析中的应用有哪些?
  • 如何在3DS上实现原生GBA硬件加速?open_agb_firm开源解决方案深度解析
  • 解决跨平台资源获取难题:res-downloader实战方案解析
  • 微信小程序逆向实战:从抓包到签名破解的完整技术解析
  • NVMe开发——从配置空间到BAR映射的PCIe设备初始化全解析