Given a dynamically linked ELF binary, say for example /bin/less
.
Inside the binary, there is a call to a function provided by a shared library, for example strcpy()
How can I find out from which shared library/shared object the strcp
function is obtained?
In other words, I want to get pairs func_name/shared_obj_name.so.
Answering this post, Michael Slade wrote:
ELF files don't specify which symbols come from which libraries; it just adds a list of shared libraries to link to into the ELF binary, and lets the linker find the symbols in the libraries.
Yet there must be a way to gather the required info (using the linker). Executing the binary and ltrace-ing it is not an option in my case. What I tried so far:
I tried objdump -T /bin/less | grep strcpy
which gives me:
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 strcpy
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.3.4 __strcpy_chk
This is neither unambigious nor does it give me the name of a .so
file.
Running ldd /bin/less
, returning:
linux-vdso.so.1 => (0x00007ffe8b7fa000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f92c23a5000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f92c1fe0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f92c25ec000))
lets me think that the "GLIBC_2.2.5" corresponds to libc.so.6
How can I programmatically find the corresponding shared object (.so file) to an (imported) function?
How can I find out from which shared library/shared object the strcp function is obtained?
In general you can't: that library can change at runtime. For example, if I compile the following source:
int strcpy(char *a, const char *src) { abort(); }
$ gcc -fPIC -shared -o foo.so foo.c
and then run your program like so:
LD_PRELOAD=./foo.so /bin/less
then the library from which strcpy
is obtained is foo.so
. Using LD_PRELOAD
this way is called library interpositioning, and is useful in all kinds of circumstances.
There are other ways to inject a different library into the process besides LD_PRELOAD
.
If you are not using any such mechanisms, and are using GLIBC, then you can ask the dynamic loader to answer that question for you. Here is one way:
LD_DEBUG=bindings ldd -r /bin/less < /dev/null |& egrep '\Wstrcpy\W'
26623: binding file /bin/bash [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `strcpy' [GLIBC_2.2.5]
26633: binding file /lib/x86_64-linux-gnu/libtinfo.so.5 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `strcpy' [GLIBC_2.2.5]
26633: binding file /bin/less [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `strcpy' [GLIBC_2.2.5]
Above you can see that ldd
invokes bash
and less
as separate processes, and both of them bind to libc.so.6
for this particular symbol.
How can I programmatically find the corresponding shared object (.so file) to an (imported) function?
If you are using GLIBC, use dladdr to "ask" the dynamic linker. Returned "info" argument will tell you the filename.