#1 楼
您可以使用ldd
命令执行此操作:NAME
ldd - print shared library dependencies
SYNOPSIS
ldd [OPTION]... FILE...
DESCRIPTION
ldd prints the shared libraries required by each program or shared
library specified on the command line.
....
示例:
$ ldd /bin/ls
linux-vdso.so.1 => (0x00007fff87ffe000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007ff0510c1000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007ff050eb9000)
libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007ff050cb0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff0508f0000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff0506ec000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff0512f7000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff0504ce000)
libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007ff0502c9000)
#2 楼
readelf -d $executable | grep 'NEEDED'
如果您无法运行可执行文件,例如是交叉编译还是不信任它:
通常情况下,ldd使用LD_TRACE_LOADED_OBJECTS调用标准动态链接器(请参阅ld.so(8))。环境变量设置为1,这将导致链接器显示库
依赖项。但是请注意,在某些情况下,ldd的某些版本可能会尝试通过直接执行程序来获取依赖项信息。因此,您应该
切勿对不受信任的可执行文件使用ldd,因为这可能会导致执行任意代码。
示例:
readelf -d /bin/ls | grep 'NEEDED'
样本输出:
0x0000000000000001 (NEEDED) Shared library: [libselinux.so.1]
0x0000000000000001 (NEEDED) Shared library: [libacl.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
请注意,库可以依赖于其他库,因此现在您需要查找依赖项。
常用的简单方法是:
$ locate libselinux.so.1
/lib/i386-linux-gnu/libselinux.so.1
/lib/x86_64-linux-gnu/libselinux.so.1
/mnt/debootstrap/lib/x86_64-linux-gnu/libselinux.so.1
,但是更精确的方法是了解
ldd
搜索路径/缓存。我认为应该是ldconfig
。选择一个,然后重复:
readelf -d /lib/x86_64-linux-gnu/libselinux.so.1 | grep 'NEEDED'
示例输出:
0x0000000000000001 (NEEDED) Shared library: [libpcre.so.3]
0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2]
等等。
另请参见:
确定Linux二进制文件的直接共享对象依赖性? |堆栈溢出
如何在C ++中找到ELF Binary所需的动态库? |堆栈溢出
如何知道ELF需要哪些动态库? |堆栈溢出
/proc/<pid>/maps
用于运行进程提到Basile,这对于查找当前正在运行的可执行文件正在使用的所有库很有用。例如:
sudo awk '/\.so/{print }' /proc/1/maps | sort -u
显示了
init
(PID 1
)当前加载的所有动态依赖项:/lib/x86_64-linux-gnu/ld-2.23.so
/lib/x86_64-linux-gnu/libapparmor.so.1.4.0
/lib/x86_64-linux-gnu/libaudit.so.1.0.0
/lib/x86_64-linux-gnu/libblkid.so.1.1.0
/lib/x86_64-linux-gnu/libc-2.23.so
/lib/x86_64-linux-gnu/libcap.so.2.24
/lib/x86_64-linux-gnu/libdl-2.23.so
/lib/x86_64-linux-gnu/libkmod.so.2.3.0
/lib/x86_64-linux-gnu/libmount.so.1.1.0
/lib/x86_64-linux-gnu/libpam.so.0.83.1
/lib/x86_64-linux-gnu/libpcre.so.3.13.2
/lib/x86_64-linux-gnu/libpthread-2.23.so
/lib/x86_64-linux-gnu/librt-2.23.so
/lib/x86_64-linux-gnu/libseccomp.so.2.2.3
/lib/x86_64-linux-gnu/libselinux.so.1
/lib/x86_64-linux-gnu/libuuid.so.1.3.0
此该方法还显示了使用
dlopen
打开的库,并通过在Ubuntu 18.04上用sleep(1000)
修改过的最小设置对其进行了测试。另请参阅:如何查看Linux中当前加载的共享库? |超级用户
评论
关于readelf方法的一个好地方是它也适用于跨二进制文件(例如:amd64上的armhf)
– Ghostrider
19年8月20日在2:21
+1用于深入了解elf二进制文件本身,而不是依赖链接程序或其他工具。
– Alireza Mohamadi
20-2-27在16:58
#3 楼
ldd和lsof显示直接或在给定时刻加载的库。他们不考虑通过dlopen
加载的库(或被dlclose
丢弃的库)。您可以使用strace
更好地了解这一情况,例如,strace -e trace=open myprogram
(因为
dlopen
最终会调用open
-尽管您当然可能拥有一个使用64的不同名称的系统位打开...)。示例:
strace -e trace=open date
向我显示此:
open("/etc/ld.so.cache", O_RDONLY) = 3
open("/lib/x86_64-linux-gnu/librt.so.1", O_RDONLY) = 3
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY) = 3
open("/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
open("/etc/localtime", O_RDONLY) = 3
Wed Apr 12 04:56:32 EDT 2017
可以从中复制“ .so”名称以查看共享的对象。
评论
一个改进:strace -e trace = open,openat myprogram
– Cyker
18年6月26日在18:04
不错的方法。 / proc /
– Ciro Santilli郝海东冠状病六四事件法轮功
18/09/13在21:27
#4 楼
lsof还可以向您显示用于某个特定进程的库。即
$ pidof nginx
6920 6919
$ lsof -p 6919|grep mem
nginx 6919 root mem REG 0,64 65960 43 /lib64/libnss_files-2.12.so
nginx 6919 root mem REG 0,64 19536 36 /lib64/libdl-2.12.so
nginx 6919 root mem REG 0,64 10312 1875 /lib64/libfreebl3.so
nginx 6919 root mem REG 0,64 1923352 38 /lib64/libc-2.12.so
nginx 6919 root mem REG 0,64 88600 1034 /lib64/libz.so.1.2.3
nginx 6919 root mem REG 0,64 1967392 1927 /usr/lib64/libcrypto.so.1.0.1e
nginx 6919 root mem REG 0,64 183080 1898 /lib64/libpcre.so.0.0.1
nginx 6919 root mem REG 0,64 40400 1217 /lib64/libcrypt-2.12.so
nginx 6919 root mem REG 0,64 142688 77 /lib64/libpthread-2.12.so
nginx 6919 root mem REG 0,64 154664 31 /lib64/ld-2.12.so
#5 楼
对于批量查询:创建一个小脚本(
useslib
)并放入PATH(或在下面的命令中指定完整路径)#! /bin/bash
ldd | grep -q
exit $?
在
find
命令中使用,例如:find /usr/bin/ -executable -type f -exec useslib {} libgtk-x11-2.0 \; -print
(libgtk-x11- 2.0似乎是gtk2 lib)
#6 楼
对于pid 1234的处理,您还可以读取/proc/1234/maps
(文本)伪文件(读取proc(5)...)或使用pmap(1),这提供了虚拟地址空间该进程,因此,这些文件(包括共享库,甚至是dlopen(3)-ed)都被映射为内存
(当然,请使用
ps aux
或pgrep(1)查找运行某些给定的进程程序)#7 楼
可以使用pmap
。例如,启动一个进程:
$ watch date
获取pid:
$ ps -ef | grep watch
显示内存映射:
$ pmap <pid>
显示完整路径:
$ pmap <pid> -p
$ pmap 72770
72770: watch date
00005613a32c9000 20K r-x-- watch
00005613a34cd000 4K r---- watch
00005613a34ce000 4K rw--- watch
00005613a4f6a000 264K rw--- [ anon ]
00007f2f3a7d5000 204616K r---- locale-archive
00007f2f46fa7000 1748K r-x-- libc-2.27.so
00007f2f4715c000 2048K ----- libc-2.27.so
00007f2f4735c000 16K r---- libc-2.27.so
00007f2f47360000 8K rw--- libc-2.27.so
00007f2f47362000 16K rw--- [ anon ]
00007f2f47366000 12K r-x-- libdl-2.27.so
00007f2f47369000 2044K ----- libdl-2.27.so
00007f2f47568000 4K r---- libdl-2.27.so
00007f2f47569000 4K rw--- libdl-2.27.so
00007f2f4756a000 160K r-x-- libtinfo.so.6.1
00007f2f47592000 2048K ----- libtinfo.so.6.1
00007f2f47792000 16K r---- libtinfo.so.6.1
00007f2f47796000 4K rw--- libtinfo.so.6.1
00007f2f47797000 232K r-x-- libncursesw.so.6.1
00007f2f477d1000 2048K ----- libncursesw.so.6.1
00007f2f479d1000 4K r---- libncursesw.so.6.1
00007f2f479d2000 4K rw--- libncursesw.so.6.1
00007f2f479d3000 148K r-x-- ld-2.27.so
00007f2f47bdb000 20K rw--- [ anon ]
00007f2f47bf1000 28K r--s- gconv-modules.cache
00007f2f47bf8000 4K r---- ld-2.27.so
00007f2f47bf9000 4K rw--- ld-2.27.so
00007f2f47bfa000 4K rw--- [ anon ]
00007ffd39404000 136K rw--- [ stack ]
00007ffd3959b000 12K r---- [ anon ]
00007ffd3959e000 8K r-x-- [ anon ]
ffffffffff600000 4K r-x-- [ anon ]
total 215692K
$ pmap 72770 -p
72770: watch date
00005613a32c9000 20K r-x-- /usr/bin/watch
00005613a34cd000 4K r---- /usr/bin/watch
00005613a34ce000 4K rw--- /usr/bin/watch
00005613a4f6a000 264K rw--- [ anon ]
00007f2f3a7d5000 204616K r---- /usr/lib/locale/locale-archive
00007f2f46fa7000 1748K r-x-- /usr/lib64/libc-2.27.so
00007f2f4715c000 2048K ----- /usr/lib64/libc-2.27.so
00007f2f4735c000 16K r---- /usr/lib64/libc-2.27.so
00007f2f47360000 8K rw--- /usr/lib64/libc-2.27.so
00007f2f47362000 16K rw--- [ anon ]
00007f2f47366000 12K r-x-- /usr/lib64/libdl-2.27.so
00007f2f47369000 2044K ----- /usr/lib64/libdl-2.27.so
00007f2f47568000 4K r---- /usr/lib64/libdl-2.27.so
00007f2f47569000 4K rw--- /usr/lib64/libdl-2.27.so
00007f2f4756a000 160K r-x-- /usr/lib64/libtinfo.so.6.1
00007f2f47592000 2048K ----- /usr/lib64/libtinfo.so.6.1
00007f2f47792000 16K r---- /usr/lib64/libtinfo.so.6.1
00007f2f47796000 4K rw--- /usr/lib64/libtinfo.so.6.1
00007f2f47797000 232K r-x-- /usr/lib64/libncursesw.so.6.1
00007f2f477d1000 2048K ----- /usr/lib64/libncursesw.so.6.1
00007f2f479d1000 4K r---- /usr/lib64/libncursesw.so.6.1
00007f2f479d2000 4K rw--- /usr/lib64/libncursesw.so.6.1
00007f2f479d3000 148K r-x-- /usr/lib64/ld-2.27.so
00007f2f47bdb000 20K rw--- [ anon ]
00007f2f47bf1000 28K r--s- /usr/lib64/gconv/gconv-modules.cache
00007f2f47bf8000 4K r---- /usr/lib64/ld-2.27.so
00007f2f47bf9000 4K rw--- /usr/lib64/ld-2.27.so
00007f2f47bfa000 4K rw--- [ anon ]
00007ffd39404000 136K rw--- [ stack ]
00007ffd3959b000 12K r---- [ anon ]
00007ffd3959e000 8K r-x-- [ anon ]
ffffffffff600000 4K r-x-- [ anon ]
total 215692K
#8 楼
我不知道ldconfig(8)的-p
选项的普及程度如何,但是如果您想避免ldd的任何安全问题,则使用readelf(1)建议和ldconfig的-p
的以下sh / awk脚本可能会有所帮助(1),还可以看到动态库的路径。 (注意:这并不会像以前那样进行包含的传递性关闭,因此您只能看到a.out直接调用的库。)#!/usr/bin/env bash
needs=`readelf -d | \
awk '=="(NEEDED)" {
gsub("[][]", "", );
hits[]=
}
END {
for (i in hits) {
printf(sprintf("%s ", i))
}
}'`
ldconfig -p | \
awk -vneeds="$needs" \
'BEGIN{
split(needs,aneeds)
}
{
if (!arr[])
arr[] = $NF
}
END {
for (i in aneeds) {
need = aneeds[i];
if (arr[need]) {
print need "\t" arr[need]
} else {
print "unfulfilled:", need
}
}
}'
例如:
{1001} ./foo.sh a.out
libc.so.6 /usr/lib/libc.so.6
libX11.so.6 /usr/lib/libX11.so.6
libgdk-3.so.0 /usr/lib/libgdk-3.so.0
libgcr-base-3.so.1 /usr/lib/libgcr-base-3.so.1
libjavascriptcoregtk-4.0.so.18 /usr/local/lib/libjavascriptcoregtk-4.0.so.18
libatk-1.0.so.0 /usr/lib/libatk-1.0.so.0
libharfbuzz.so.0 /usr/lib/libharfbuzz.so.0
libsoup-2.4.so.1 /usr/lib/libsoup-2.4.so.1
libgdk_pixbuf-2.0.so.0 /usr/lib/libgdk_pixbuf-2.0.so.0
libgck-1.so.0 /usr/lib/libgck-1.so.0
libgthread-2.0.so.0 /usr/lib/libgthread-2.0.so.0
libgcr-ui-3.so.1 /usr/lib/libgcr-ui-3.so.1
libglib-2.0.so.0 /usr/lib/libglib-2.0.so.0
libgobject-2.0.so.0 /usr/lib/libgobject-2.0.so.0
libcairo-gobject.so.2 /usr/lib/libcairo-gobject.so.2
libpango-1.0.so.0 /usr/lib/libpango-1.0.so.0
libz.so.1 /usr/lib/libz.so.1
libgio-2.0.so.0 /usr/lib/libgio-2.0.so.0
libpangocairo-1.0.so.0 /usr/lib/libpangocairo-1.0.so.0
libp11-kit.so.0 /usr/lib/libp11-kit.so.0
libcairo.so.2 /usr/lib/libcairo.so.2
libgtk-3.so.0 /usr/lib/libgtk-3.so.0
libwebkit2gtk-4.0.so.37 /usr/local/lib/libwebkit2gtk-4.0.so.37
评论
任何关于macOS等同于此的想法吗?它不会在达尔文上出现lld,也无法通过自制程序找到它。
– mz2
16-10-23在14:05
在macOS上:otool -L <二进制路径>
–理查德·维尼(Richard Viney)
17 Mar 17 '17 at 22:23
请注意,这可能会执行二进制文件。因此,如果二进制文件不受信任,最好不使用ldd。请参见手册页。
–保罗·鲁尼
19年8月19日在2:57
要遵循@PaulRooney的评论:特别是,手册页建议使用objdump -p / path / to / program |如果您不信任可执行文件,则需要grep来替代ldd。
–乔什·戴斯蒙德(Josh Desmond)
20-4-4在21:56
我使用此代码片段找到了部门,然后将其复制到我的监狱... ldd $ {jail} / bin / * | egrep -o'\ [^ \] * / lib \ [^ \] * \ [。\] \ [0-9 \]'| xargs -I {} -P1 sudo cp -v {} $ {jail} {}
–理查德
20年4月14日在23:20