如何找出程序或其他库使用的共享对象的哪些函数?

25
我该如何找到一个程序或另一个库使用的共享对象中的哪些函数? 在这个具体的情况下,我想知道在 /lib/libgcc1_s.so.1 中的哪些函数被另一个动态库使用。 由于它们是动态链接的,objdump -d 无法解析函数调用地址。 除了在调试器中运行程序或静态地重新链接之外,是否有其他方法? 谢谢,
Luca
编辑:
nm 和 readelf 不起作用,我不需要看到共享对象中存在哪些符号,而是需要看到哪些符号实际上被链接到它的另一个对象中使用。
5个回答

48

nm 只有在库中没有剥离其符号的情况下才能发挥作用。 然而,nm -D 可以显示一些信息:

nm -D /lib/libgcc_s.so.1

但是还有另一种工具可以帮助您:readelf

readelf - 显示关于 ELF 文件的信息。

如果您查看 man 页面,选项-s: 显示文件中符号表部分的条目(如果有)。

readelf -s /lib/libgcc_s.so.1

编辑:

如果您在使用nm检查对象时发现未实现的符号,它们将在前面带有U标志,但nm不会告诉您系统上哪个库实现了该符号。

因此,您可能需要结合使用lddnm来查找所需内容。ldd会告诉您应用程序链接的库,而nm会告诉您哪些符号未定义(U标志)或在本地实现(T标志)。

在列出目标应用程序上所有未定义的符号(使用nm)后,您应该遍历所有由ldd报告的库,以查找这些符号(再次使用nm)。如果您找到符号并且其前面带有T标志,则找到了该符号。

顺便说一下,我刚刚为bash编写了一个单行代码,以说明我的想法。它分析了一个名为win的应用程序,并尝试找到实现所有未定义符号的库。

target="win"; for symbol in $(nm -D $target | grep "U " | cut -b12-); do for library in $(ldd $target | cut -d ' ' -f3- | cut -d' ' -f1); do for lib_symbol in $(nm -D $library | grep "T " | cut -b12-); do if [ $symbol == $lib_symbol ]; then echo "Found symbol: $symbol at [$library]"; fi ; done; done; done;

或者,如果您的终端支持颜色:

target="win"; for symbol in $(nm -D $target | grep "U " | cut -b12-); do for library in $(ldd $target | cut -d ' ' -f3- | cut -d' ' -f1); do for lib_symbol in $(nm -D $library | grep "T " | cut -b12-); do if [ $symbol == $lib_symbol ]; then echo -e "Found symbol: \e[1;36m$symbol\033[0m at \e[1;34m$library\033[0m"; fi ; done; done; done;

我相信会有人发现性能提升。
输出:
Found symbol: XCreateColormap at [/usr/lib/libX11.so.6]
Found symbol: XCreateWindow at [/usr/lib/libX11.so.6]
Found symbol: XIfEvent at [/usr/lib/libX11.so.6]
Found symbol: XMapWindow at [/usr/lib/libX11.so.6]
Found symbol: XOpenDisplay at [/usr/lib/libX11.so.6]
Found symbol: __libc_start_main at [/lib/tls/i686/cmov/libc.so.6]
Found symbol: __stack_chk_fail at [/lib/tls/i686/cmov/libc.so.6]
Found symbol: glClear at [/usr/lib/mesa/libGL.so.1]
Found symbol: glClearColor at [/usr/lib/mesa/libGL.so.1]
Found symbol: glFlush at [/usr/lib/mesa/libGL.so.1]
Found symbol: glXChooseFBConfig at [/usr/lib/mesa/libGL.so.1]
Found symbol: glXChooseVisual at [/usr/lib/mesa/libGL.so.1]
Found symbol: glXCreateContext at [/usr/lib/mesa/libGL.so.1]
Found symbol: glXCreateNewContext at [/usr/lib/mesa/libGL.so.1]
Found symbol: glXCreateWindow at [/usr/lib/mesa/libGL.so.1]
Found symbol: glXGetVisualFromFBConfig at [/usr/lib/mesa/libGL.so.1]
Found symbol: glXMakeContextCurrent at [/usr/lib/mesa/libGL.so.1]
Found symbol: glXMakeCurrent at [/usr/lib/mesa/libGL.so.1]
Found symbol: glXQueryVersion at [/usr/lib/mesa/libGL.so.1]

@lultimouomo 我更新了我的答案,并添加了一个Bash的一行代码,让你可以开始使用。 - karlphillip
我也使用 readelf 命令,同时加上 -W 参数(允许输出宽度超过80个字符)。 - pevik
3
请参见 https://gist.github.com/toojays/dffd9b806692a10649c1fcd146ee7866,该实现速度更快,采用了类似的方法。 - toojays

5
你看过 ltrace 吗?它可以在运行时拦截共享库函数的调用并打印相关信息。
由于这是一种动态解决方案,它不会为程序中从未执行的部分所做的库调用打印任何信息。但根据你的需求,它可能仍然有所帮助。

1

我不知道有没有一个,即使nm对于你似乎打算使用的目的也有限。此外,预加载(GNU链接器)可能会使你在使用一个据称可以做到这一点的工具之后所做的任何假设失效。请参阅ld.so man pageLD_PRELOAD可以被任何人用来覆盖正常情况下发生的符号解析。

然而,即使没有调试器,你也可以使用LD_DEBUG来查看最终使用了哪个函数。


0
也许 nm 工具可以帮助你,因为它显示了二进制文件中包含的符号名称。
使用起来简单明了:
nm my_binary

0

这可以通过逆向工程中的静态分析技术来实现。

为此,您需要使用反汇编器。请参阅http://en.wikipedia.org/wiki/Disassembler

IDA PRO是一个很好的反汇编程序,可以回答您的问题。它能够读取ELF文件格式,但不幸的是它并非免费。


2
每个经验丰富的逆向工程师都会非常挑剔地选择分析什么(以及如何分析)。你建议的需要进行全面分析。这对于某些软件来说是可以完成的,但很少见,因为这需要大量的工作。静态分析并不是要实现提问者想要达到的目标的好建议。 - 0xC0000022L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接