如何使用LD_PRELOAD检查是否已预加载Linux共享库

时间:2022-08-01 07:03:05

I'm familiar with using dlopen() to check if a shared library has been loaded into a process using a prior call to dlopen() without triggering a load if it isn't present, like so:

我熟悉使用dlopen()检查共享库是否已经使用先前调用dlopen()加载到进程中,如果不存在则不会触发加载,如下所示:

 void* lib = dlopen(lib_name, RTLD_NOLOAD);
 if (lib != NULL) {
   ...
 }

I've recently tried to apply the same pattern to determine if one of a handful of shared libraries have been loaded into a process space using LD_PRELOAD. However in all the cases, the above mentioned call to dlopen() returns NULL.

我最近尝试应用相同的模式来确定是否已使用LD_PRELOAD将少数共享库中的一个加载到进程空间中。但是在所有情况下,上面提到的对dlopen()的调用都返回NULL。

So basically, if I start the process using this command line

所以基本上,如果我使用这个命令行启动进程

LD_PRELOAD=libawesome.so ./mycoolprocess

and then run the following check in the code in mycoolprocess.c

然后在mycoolprocess.c中的代码中运行以下检查

void* has_awesome = dlopen("libawesome.so", RTLD_NOLOAD);
if (has_awesome != NULL) {
  printf("libawesome is available\n");
}

the call to dlopen() always returns NULL no matter if the shared library has been loaded using LD_PRELOAD or not. Based on Andrew Henle's comment below I also tried calling dlopen with the absolute path to one of the reloaded shared objects, but dlopen in this case still returns NULL despite the shared object being preloaded.

无论是否使用LD_PRELOAD加载了共享库,对dlopen()的调用始终返回NULL。根据Andrew Henle在下面的评论,我也尝试使用其中一个重新加载的共享对象的绝对路径调用dlopen,但是在这种情况下dlopen仍然返回NULL,尽管共享对象是预加载的。

So my question is twofold:

所以我的问题是双重的:

  1. Should the above pattern work for a library that's been loaded using LD_PRELOAD?
  2. 上述模式是否适用于使用LD_PRELOAD加载的库?

  3. Is there another way to have a process determine if a specific shared library has been preloaded?
  4. 是否有另一种方法让进程确定是否已预加载特定的共享库?

1 个解决方案

#1


2  

No and yes, respectively.

不,是的,分别。

dlopen() and the LD_PRELOAD trick, although they both deal with shared libraries, operate in fundamentally different ways.

dlopen()和LD_PRELOAD技巧虽然它们都处理共享库,但却以完全不同的方式运行。

The LD_PRELOAD environment variable is handled by the dynamic linker/loader (ld-linux.so), and affects the resolution of relocation records in the executable binary itself. In a nutshell, at every point in your code where there's a call to a function that's defined in a dynamic library, the linker (at build time) will insert a placeholder for the memory address to jump to. At runtime, those placeholders are replaced by real addresses based on the shared libraries loaded into memory, which are themselves named in the executable, but may be overridden if LD_PRELOAD is used.

LD_PRELOAD环境变量由动态链接器/加载器(ld-linux.so)处理,并影响可执行二进制文件本身中的重定位记录的解析。简而言之,在代码中调用动态库中定义的函数的每个点,链接器(在构建时)将插入占位符以便跳转到内存地址。在运行时,这些占位符由基于加载到内存中的共享库的实际地址替换,这些共享库本身在可执行文件中命名,但如果使用LD_PRELOAD则可以覆盖。

So once the executable is loaded into memory and all those placeholders have been filled in with real addresses, there's no simple (or portable) way of telling what came from where. However...

因此,一旦将可执行文件加载到内存中并且所有这些占位符都填充了真实地址,就没有简单的(或可移植的)方式来告诉来自哪里。然而...

You could examine the running process' memory map. On Linux, this would mean parsing through /proc/<pid>/maps. The file contents are fairly self-explanatory, so just pick one at random and take a look.

您可以检查正在运行的进程的内存映射。在Linux上,这意味着通过/ proc / / maps进行解析。文件内容是相当不言自明的,所以只需随机选择一个并查看。

No idea how you'd do it on other systems, but I believe most modern unixen have a /proc filesystem of some sort.

不知道你是如何在其他系统上做的,但我相信大多数现代unixen都有某种/ proc文件系统。

#1


2  

No and yes, respectively.

不,是的,分别。

dlopen() and the LD_PRELOAD trick, although they both deal with shared libraries, operate in fundamentally different ways.

dlopen()和LD_PRELOAD技巧虽然它们都处理共享库,但却以完全不同的方式运行。

The LD_PRELOAD environment variable is handled by the dynamic linker/loader (ld-linux.so), and affects the resolution of relocation records in the executable binary itself. In a nutshell, at every point in your code where there's a call to a function that's defined in a dynamic library, the linker (at build time) will insert a placeholder for the memory address to jump to. At runtime, those placeholders are replaced by real addresses based on the shared libraries loaded into memory, which are themselves named in the executable, but may be overridden if LD_PRELOAD is used.

LD_PRELOAD环境变量由动态链接器/加载器(ld-linux.so)处理,并影响可执行二进制文件本身中的重定位记录的解析。简而言之,在代码中调用动态库中定义的函数的每个点,链接器(在构建时)将插入占位符以便跳转到内存地址。在运行时,这些占位符由基于加载到内存中的共享库的实际地址替换,这些共享库本身在可执行文件中命名,但如果使用LD_PRELOAD则可以覆盖。

So once the executable is loaded into memory and all those placeholders have been filled in with real addresses, there's no simple (or portable) way of telling what came from where. However...

因此,一旦将可执行文件加载到内存中并且所有这些占位符都填充了真实地址,就没有简单的(或可移植的)方式来告诉来自哪里。然而...

You could examine the running process' memory map. On Linux, this would mean parsing through /proc/<pid>/maps. The file contents are fairly self-explanatory, so just pick one at random and take a look.

您可以检查正在运行的进程的内存映射。在Linux上,这意味着通过/ proc / / maps进行解析。文件内容是相当不言自明的,所以只需随机选择一个并查看。

No idea how you'd do it on other systems, but I believe most modern unixen have a /proc filesystem of some sort.

不知道你是如何在其他系统上做的,但我相信大多数现代unixen都有某种/ proc文件系统。