如何显示Linux可执行文件使用的所有共享库?


225

我想知道系统上的可执行文件使用了哪些库。更具体地说,我想对使用最多的库以及使用它们的二进制文件进行排名。我怎样才能做到这一点?


如果可执行文件使用,您可能将无法获得确切的数字dlopen
jxh

Answers:


271
  1. 使用ldd到列表共享为每个可执行文件库。
  2. 清理输出
  3. 排序,计算计数,按计数排序

要在“ / bin”目录中找到所有可执行文件的答案:

find /bin -type f -perm /a+x -exec ldd {} \; \
| grep so \
| sed -e '/^[^\t]/ d' \
| sed -e 's/\t//' \
| sed -e 's/.*=..//' \
| sed -e 's/ (0.*)//' \
| sort \
| uniq -c \
| sort -n

将上面的“ / bin”更改为“ /”以搜索所有目录。

输出(仅针对/ bin目录)将如下所示:

  1 /lib64/libexpat.so.0
  1 /lib64/libgcc_s.so.1
  1 /lib64/libnsl.so.1
  1 /lib64/libpcre.so.0
  1 /lib64/libproc-3.2.7.so
  1 /usr/lib64/libbeecrypt.so.6
  1 /usr/lib64/libbz2.so.1
  1 /usr/lib64/libelf.so.1
  1 /usr/lib64/libpopt.so.0
  1 /usr/lib64/librpm-4.4.so
  1 /usr/lib64/librpmdb-4.4.so
  1 /usr/lib64/librpmio-4.4.so
  1 /usr/lib64/libsqlite3.so.0
  1 /usr/lib64/libstdc++.so.6
  1 /usr/lib64/libz.so.1
  2 /lib64/libasound.so.2
  2 /lib64/libblkid.so.1
  2 /lib64/libdevmapper.so.1.02
  2 /lib64/libpam_misc.so.0
  2 /lib64/libpam.so.0
  2 /lib64/libuuid.so.1
  3 /lib64/libaudit.so.0
  3 /lib64/libcrypt.so.1
  3 /lib64/libdbus-1.so.3
  4 /lib64/libresolv.so.2
  4 /lib64/libtermcap.so.2
  5 /lib64/libacl.so.1
  5 /lib64/libattr.so.1
  5 /lib64/libcap.so.1
  6 /lib64/librt.so.1
  7 /lib64/libm.so.6
  9 /lib64/libpthread.so.0
 13 /lib64/libselinux.so.1
 13 /lib64/libsepol.so.1
 22 /lib64/libdl.so.2
 83 /lib64/ld-linux-x86-64.so.2
 83 /lib64/libc.so.6

编辑-删除了“ grep -P”


2
这是一个很好的答案(我已投票赞成),但是您能解释一下“ grep -P'\ t。* so'”命令吗?据man称,这将模式解释为perl regexp,但是我的grep版本不支持它(man表示这是一个普遍问题)。Perl特定于regexp的哪一部分?
鲍比·杰克

2
我认为您可能需要使用ldd -v
MountainX,

56
请注意,ldd实际上是使用特殊的环境变量来运行可执行文件,并且Linux动态链接器会识别此标志并仅输出库而不是运行可执行文件。看来源ldd; 在我的系统上,这是一个bash脚本。如果可执行文件是静态链接的,并且使用syscalls,并指定了其他加载程序,则它可以执行任意恶意的操作。因此,请勿ldd在您不信任的可执行文件上使用。
巴里·凯利

“ ldd”不适用于交叉编译的二进制文件。问题是要找到当前系统上的程序使用的库(如所说的那样,将是本机程序)。这是一个很好的答案。但是,我想我要提到的是,如果要为其他系统的程序寻找共享库(在另一个答案中提到的“ readelf”对我有用),您需要使用其他东西
Tim Bird,

68

我的ARM工具链上没有ldd,因此我使用objdump:

$(CROSS_COMPILE)objdump -p

例如:

objdump -p /usr/bin/python:

Dynamic Section:
  NEEDED               libpthread.so.0
  NEEDED               libdl.so.2
  NEEDED               libutil.so.1
  NEEDED               libssl.so.1.0.0
  NEEDED               libcrypto.so.1.0.0
  NEEDED               libz.so.1
  NEEDED               libm.so.6
  NEEDED               libc.so.6
  INIT                 0x0000000000416a98
  FINI                 0x000000000053c058
  GNU_HASH             0x0000000000400298
  STRTAB               0x000000000040c858
  SYMTAB               0x0000000000402aa8
  STRSZ                0x0000000000006cdb
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  PLTGOT               0x0000000000832fe8
  PLTRELSZ             0x0000000000002688
  PLTREL               0x0000000000000007
  JMPREL               0x0000000000414410
  RELA                 0x0000000000414398
  RELASZ               0x0000000000000078
  RELAENT              0x0000000000000018
  VERNEED              0x0000000000414258
  VERNEEDNUM           0x0000000000000008
  VERSYM               0x0000000000413534

2
这也应该是安全的,不像ldd不应该在不受信任的可执行文件上使用。
PSkocik

此外,obbjdump -p还会显示诸如的其他信息RPATH,这对于调查可执行文件的动态链接问题可能会有帮助。
sitaktif

为实际上安全可靠的方法+1(我以某种方式获得了一个musl-gcc定期生成二进制文件的系统,以至于调用ldd二进制文件只会执行二进制文件,因此,如今,我经常想起不安全的ldd情况)。
mtraceur '19


48

要了解二进制文件使用的库,请使用ldd

ldd path/to/the/tool

您必须编写一些shell脚本才能了解系统范围的故障。


19

检查程序可执行文件的共享库依赖关系

要找出特定可执行文件所依赖的库,可以使用ldd命令。此命令调用动态链接器以查找可执行文件的库依赖关系。

> $ ldd / path / to / program

请注意,不建议对任何不受信任的第三方可执行文件运行ldd,因为某些版本的ldd可能会直接调用该可执行文件以识别其库依赖关系,这可能会带来安全风险。

相反,一种显示未知应用程序二进制文件的库依赖关系的更安全方法是使用以下命令。

$ objdump -p / path / to / program | 需要grep

了解更多信息


14

readelf -d 递归

redelf -d产生的输出类似于objdump -phttps://stackoverflow.com/a/15520982/895245中提到的输出

但是要注意,动态库可能依赖于其他动态库,因此必须递归。

例:

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

选择一个,然后重复:

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]

等等。

/proc/<pid>/maps 用于运行流程

这对于查找正在运行的可执行文件当前正在使用的所有库很有用。例如:

sudo awk '/\.so/{print $6}' /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上通过hack的最小设置进行了测试sleep(1000)

另请参阅:https : //superuser.com/questions/310199/see-currently-loaded-shared-objects-in-linux/1243089


7

在OS X上默认是没有lddobjdumplsof。或者,尝试otool -L

$ otool -L `which openssl`
/usr/bin/openssl:
    /usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8)
    /usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)

在此示例中,使用which openssl填充给定可执行文件和当前用户环境的标准路径。


6

在UNIX系统上,假设二进制(可执行)名称为test。然后我们使用以下命令列出测试中使用的库

ldd test

4

有了ldd您,您可以获得工具使用的库。要对一组工具的库使用情况进行排名,可以使用以下命令。

ldd /bin/* /usr/bin/* ... | sed -e '/^[^\t]/ d; s/^\t\(.* => \)\?\([^ ]*\) (.*/\2/g' | sort | uniq -c

(在这里sed删除了所有不以制表符开头的行,并且仅过滤出实际的库。sort | uniq -c获得每个库时,都有一个计数来指示发生的次数。)

您可能需要sort -g在最后添加以按使用顺序获取库。

请注意,使用上述命令您可能会获得两行非库行。一种是静态可执行文件(“不是动态可执行文件”),另一种是没有任何库。后者的结果是linux-gate.so.1它不是文件系统中的库,而是内核“提供”的一个库。


2

可以再读取一个文件,该文件位于

/proc/<pid>/maps

例如,进程ID为2601,则命令为

cat /proc/2601/maps

和输出就像

7fb37a8f2000-7fb37a8f4000 r-xp 00000000 08:06 4065647                    /usr/lib/x86_64-linux-gnu/libproxy/0.4.15/modules/network_networkmanager.so
7fb37a8f4000-7fb37aaf3000 ---p 00002000 08:06 4065647                    /usr/lib/x86_64-linux-gnu/libproxy/0.4.15/modules/network_networkmanager.so
7fb37aaf3000-7fb37aaf4000 r--p 00001000 08:06 4065647                    /usr/lib/x86_64-linux-gnu/libproxy/0.4.15/modules/network_networkmanager.so
7fb37aaf4000-7fb37aaf5000 rw-p 00002000 08:06 4065647                    /usr/lib/x86_64-linux-gnu/libproxy/0.4.15/modules/network_networkmanager.so
7fb37aaf5000-7fb37aafe000 r-xp 00000000 08:06 4065646                    /usr/lib/x86_64-linux-gnu/libproxy/0.4.15/modules/config_gnome3.so
7fb37aafe000-7fb37acfd000 ---p 00009000 08:06 4065646                    /usr/lib/x86_64-linux-gnu/libproxy/0.4.15/modules/config_gnome3.so
7fb37acfd000-7fb37acfe000 r--p 00008000 08:06 4065646                    /usr/lib/x86_64-linux-gnu/libproxy/0.4.15/modules/config_gnome3.so
7fb37acfe000-7fb37acff000 rw-p 00009000 08:06 4065646                    /usr/lib/x86_64-linux-gnu/libproxy/0.4.15/modules/config_gnome3.so
7fb37acff000-7fb37ad1d000 r-xp 00000000 08:06 3416761                    /usr/lib/x86_64-linux-gnu/libproxy.so.1.0.0
7fb37ad1d000-7fb37af1d000 ---p 0001e000 08:06 3416761                    /usr/lib/x86_64-linux-gnu/libproxy.so.1.0.0
7fb37af1d000-7fb37af1e000 r--p 0001e000 08:06 3416761                    /usr/lib/x86_64-linux-gnu/libproxy.so.1.0.0
7fb37af1e000-7fb37af1f000 rw-p 0001f000 08:06 3416761                    /usr/lib/x86_64-linux-gnu/libproxy.so.1.0.0
7fb37af1f000-7fb37af21000 r-xp 00000000 08:06 4065186                    /usr/lib/x86_64-linux-gnu/gio/modules/libgiolibproxy.so
7fb37af21000-7fb37b121000 ---p 00002000 08:06 4065186                    /usr/lib/x86_64-linux-gnu/gio/modules/libgiolibproxy.so
7fb37b121000-7fb37b122000 r--p 00002000 08:06 4065186                    /usr/lib/x86_64-linux-gnu/gio/modules/libgiolibproxy.so
7fb37b122000-7fb37b123000 rw-p 00003000 08:06 4065186                    /usr/lib/x86_64-linux-gnu/gio/modules/libgiolibproxy.so


0

我发现这篇文章非常有帮助,因为我需要研究来自第三方提供的库的依赖关系(32位对64位执行路径)。

我根据RHEL 6发行版上的“ readelf -d”建议,整理了一个Q&D递归bash脚本。

这是非常基本的,并且每次都会测试每个依赖关系,即使它以前可能已经被测试过(即非常冗长)。输出也是非常基本的。

#! /bin/bash

recurse ()
# Param 1 is the nuumber of spaces that the output will be prepended with
# Param 2 full path to library
{
#Use 'readelf -d' to find dependencies
dependencies=$(readelf -d ${2} | grep NEEDED | awk '{ print $5 }' | tr -d '[]')
for d in $dependencies; do
   echo "${1}${d}"
   nm=${d##*/}
   #libstdc++ hack for the '+'-s
   nm1=${nm//"+"/"\+"}
   # /lib /lib64 /usr/lib and /usr/lib are searched
   children=$(locate ${d} | grep -E "(^/(lib|lib64|usr/lib|usr/lib64)/${nm1})")
   rc=$?
   #at least locate... didn't fail
   if [ ${rc} == "0" ] ; then
      #we have at least one dependency
      if [ ${#children[@]} -gt 0 ]; then
         #check the dependeny's dependencies
         for c in $children; do
          recurse "  ${1}" ${c}
         done
      else
         echo "${1}no children found"
      fi
   else
      echo "${1}locate failed for ${d}"
   fi
done
}
# Q&D -- recurse needs 2 params could/should be supplied from cmdline
recurse "" !!full path to library you want to investigate!!

将输出重定向到文件并grep表示“找到”或“失败”

您随意使用和修改,后果自负。

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.