LD_PRELOAD技巧是什么?


341

我最近在proggit上遇到了对它的引用,并且(到目前为止)没有对其进行解释。

我猜测 可能是吧,但我不知道。


1
这并不是一个真正的答案,所以我不会将它发布为一个。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。似乎正在使用liballocs,因此其他动态语言可以相互交谈。本演讲中有一些深入的内部解释。 youtu.be/LwicN2u6Dro?t=24m10s
Elijah

Answers:


415

如果设置LD_PRELOAD为共享库的路径,则该文件将任何其他库(包括C运行时libc.so之前加载。因此,要运行ls您的特殊malloc()实现,请执行以下操作:

$ LD_PRELOAD=/path/to/my/malloc.so /bin/ls

12
我不知道它的存在……似乎它将成为安全攻击的主要媒介。知道如何保护它吗?
rmeador

141
这是有保障的,因为如果ruid!= euid,加载程序将忽略LD_PRELOAD-约书亚
约书亚2009年

18
@约书亚:什么是鲁伊德和厄伊德?
heinrich5991 2012年

20
@ heinrich5991真实有效的用户ID:lst.de/~okir/blackhats/node23.html
gsingh2011 2013年

59
要记住的一件事:您通常要指定的绝对路径LD_PRELOAD。原因是它是一个环境变量,由子进程继承-子进程的工作目录可能不同于父进程。因此,任何相对路径都将无法找到要预加载的库。
Frerich Raabe 2013年

49

通过创建具有相同符号的库并在中指定库,可以覆盖库存库中的符号LD_PRELOAD

有人用它在非标准位置指定库,但是这样LD_LIBRARY_PATH做更好。


17
“有人使用它在非标准位置指定库” ...真的吗?听起来像“有人用错了”!
汤姆(Tom)

6
LD_PRELOAD可以凭借加载顺序来拦截应用程序指定的硬编码路径。
约书亚

1
假设库兼容,则预加载不同版本的库是否会被滥用?
z0r13年

2
我已经看到它曾经用来加载调试或检测变量,或者用来加载与基础库完全不同的库,就像模拟其他系统一样。
约书亚

1
在库编译不正确的情况下(用来与mysql一直碰到的是,它一直与通用libmysql_client松散耦合,从而覆盖了旧版本的符号链接-取决于您必须指定的perl版本) /与LD_PRELOAD ..有用的技巧迫使它如果我没有记错,Valgrind的使用此技术来提供调试能力的二进制文件,而无需重新编译..这是相当有用的。
synthesizerpatel

37

有了LD_PRELOAD您就可以赋予图书馆优先权。

例如,您可以编写一个实现malloc和的库free。并且通过将这些加载到LD_PRELOAD您的中mallocfree将执行它们而不是标准的。


但是,如果程序使用该calloc怎么办?那会不会把一切搞砸了?
Janus Troelsen 2014年

7
@JanusTroelsen如果您编写的库未实现特定部分,则将从原始库中加载该部分。
Woodrow Barlow 2014年

@JanusTroelsen,换句话说,LD_PRELOAD允许您指定使用特定符号的哪种实现。如果预加载的库未导出符号,则会在其他位置找到它。
sherrellbc

1
@JanusTroelsen:事实证明,mallocfree是在glibc中专门设计的,以允许这样做,并且库存calloc设法调用了import malloc。不要将其与其他任何功能一起尝试。它不会那么好用。
约书亚

30

正如很多人提到的,LD_PRELOAD用于预加载库。顺便说一句,您可以通过命令检查设置是否可用ldd

示例:假设您需要预载自己的libselinux.so.1

> ldd /bin/ls
    ...
    libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f3927b1d000)
    libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007f3927914000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f392754f000)
    libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f3927311000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f392710c000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f3927d65000)
    libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007f3926f07000)

因此,设置您的预加载环境:

  export LD_PRELOAD=/home/patric/libselinux.so.1

再次检查您的图书馆:

>ldd /bin/ls
    ...
    libselinux.so.1 =>
    /home/patric/libselinux.so.1 (0x00007fb9245d8000)
    ...

9

LD_PRELOAD列出共享库,其功能会覆盖标准集,就像这样/etc/ld.so.preload做一样。这些由加载程序实现/lib/ld-linux.so。如果您只想覆盖几个选定的函数,则可以通过创建一个覆盖对象文件并设置LD_PRELOAD ;来实现。该对象文件中的函数将仅覆盖那些保留其他函数的函数。

有关共享库的更多信息,请访问 http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html



3

导出mylib.so到环境很容易:

$ export LD_PRELOAD=/path/mylib.so
$ ./mybin

禁用:

$ export LD_PRELOAD=

7
unset LD_PRELOAD
Morten

2

当使用LD_PRELOAD时,该文件将在任何其他$export LD_PRELOAD=/path/liblib被预加载之前 被加载,即使它也可以在程序中使用


1

使用LD_PRELOAD路径,您可以强制应用程序加载器加载提供的共享对象,而不是提供的默认对象。

开发人员使用它通过提供不同版本的共享库来调试其应用程序。

通过使用准备好的共享对象覆盖现有功能,我们已使用它来入侵某些应用程序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.