如何检查 linux 共享库是否已使用 LD_PRELOAD 预加载
How to check if a linux shared library has been preloaded using LD_PRELOAD
我熟悉使用 dlopen()
检查共享库是否已加载到使用先前调用 dlopen()
的进程中,如果它不存在则不触发加载,例如所以:
void* lib = dlopen(lib_name, RTLD_NOLOAD);
if (lib != NULL) {
...
}
我最近尝试应用相同的模式来确定少数共享库之一是否已使用 LD_PRELOAD 加载到进程 space 中。但是在所有情况下,上面提到的对 dlopen()
returns NULL
.
的调用
基本上,如果我使用此命令行启动进程
LD_PRELOAD=libawesome.so ./mycoolprocess
然后运行下面的代码在mycoolprocess.c
中检查
void* has_awesome = dlopen("libawesome.so", RTLD_NOLOAD);
if (has_awesome != NULL) {
printf("libawesome is available\n");
}
无论是否使用 LD_PRELOAD 加载共享库,对 dlopen()
的调用总是 returns NULL
。根据 Andrew Henle 下面的评论,我还尝试使用重新加载的共享对象之一的绝对路径调用 dlopen
,但在这种情况下 dlopen
仍然是 returns NULL,尽管预加载了共享对象。
所以我的问题是双重的:
- 上述模式是否适用于使用 LD_PRELOAD 加载的库?
- 是否有另一种方法可以让进程确定是否已预加载特定的共享库?
分别是否和是。
dlopen()
和 LD_PRELOAD 技巧,虽然它们都处理共享库,但操作方式根本不同。
LD_PRELOAD 环境变量由动态 linker/loader (ld-linux.so) 处理,并影响可执行二进制文件本身中重定位记录的解析。简而言之,在代码中调用动态库中定义的函数的每个点,链接器(在构建时)都会为要跳转到的内存地址插入一个占位符。在运行时,这些占位符被基于加载到内存中的共享库的真实地址替换,它们本身在可执行文件中命名,但如果使用 LD_PRELOAD 可能会被覆盖。
因此,一旦可执行文件被加载到内存中并且所有这些占位符都已填充了真实地址,就没有简单(或可移植)的方式来判断什么来自哪里。然而...
您可以检查运行进程的内存映射。在 Linux 上,这意味着通过 /proc//maps 进行解析。文件内容一目了然,随便挑一个看一看。
不知道如何在其他系统上执行此操作,但我相信大多数现代 unixen 都有某种 /proc 文件系统。
我熟悉使用 dlopen()
检查共享库是否已加载到使用先前调用 dlopen()
的进程中,如果它不存在则不触发加载,例如所以:
void* lib = dlopen(lib_name, RTLD_NOLOAD);
if (lib != NULL) {
...
}
我最近尝试应用相同的模式来确定少数共享库之一是否已使用 LD_PRELOAD 加载到进程 space 中。但是在所有情况下,上面提到的对 dlopen()
returns NULL
.
基本上,如果我使用此命令行启动进程
LD_PRELOAD=libawesome.so ./mycoolprocess
然后运行下面的代码在mycoolprocess.c
中检查void* has_awesome = dlopen("libawesome.so", RTLD_NOLOAD);
if (has_awesome != NULL) {
printf("libawesome is available\n");
}
无论是否使用 LD_PRELOAD 加载共享库,对 dlopen()
的调用总是 returns NULL
。根据 Andrew Henle 下面的评论,我还尝试使用重新加载的共享对象之一的绝对路径调用 dlopen
,但在这种情况下 dlopen
仍然是 returns NULL,尽管预加载了共享对象。
所以我的问题是双重的:
- 上述模式是否适用于使用 LD_PRELOAD 加载的库?
- 是否有另一种方法可以让进程确定是否已预加载特定的共享库?
分别是否和是。
dlopen()
和 LD_PRELOAD 技巧,虽然它们都处理共享库,但操作方式根本不同。
LD_PRELOAD 环境变量由动态 linker/loader (ld-linux.so) 处理,并影响可执行二进制文件本身中重定位记录的解析。简而言之,在代码中调用动态库中定义的函数的每个点,链接器(在构建时)都会为要跳转到的内存地址插入一个占位符。在运行时,这些占位符被基于加载到内存中的共享库的真实地址替换,它们本身在可执行文件中命名,但如果使用 LD_PRELOAD 可能会被覆盖。
因此,一旦可执行文件被加载到内存中并且所有这些占位符都已填充了真实地址,就没有简单(或可移植)的方式来判断什么来自哪里。然而...
您可以检查运行进程的内存映射。在 Linux 上,这意味着通过 /proc/
不知道如何在其他系统上执行此操作,但我相信大多数现代 unixen 都有某种 /proc 文件系统。