Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to "statically" interpose a shared .so (or .o) library into an executable?

First of all, consider the following case.

Below is a program:

// test.cpp
extern "C" void printf(const char*, ...);

int main() {
        printf("Hello");
}

Below is a library:

// ext.cpp (the external library)
#include <iostream>

extern "C" void printf(const char* p, ...);

void printf(const char* p, ...) {
        std::cout << p << " World!\n";
}

Now I can compile the above program and library in two different ways.

The first way is to compile the program without linking the external library:

$ g++ test.cpp -o test
$ ldd test
        linux-gate.so.1 =>  (0xb76e8000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7518000)
        /lib/ld-linux.so.2 (0xb76e9000)

If I run the above program, it will print:

$ ./test 
Hello

The second way is to compile the program with a link to the external library:

$ g++ -shared -fPIC ext.cpp -o libext.so
$ g++ test.cpp -L./ -lext  -o test
$ export LD_LIBRARY_PATH=./
$ ldd test
        linux-gate.so.1 =>  (0xb773e000)
        libext.so => ./libext.so (0xb7738000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb756b000)
        libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xb7481000)
        /lib/ld-linux.so.2 (0xb773f000)
        libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb743e000)
        libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb7421000)
$ ./test
Hello World!

As you can see, in the first case the program uses printf from libc.so, while in the second case it uses printf from libext.so.

My question is: from the executable obtained as in the first case and the object code of libext (either as .so or .o), is it possible to obtain an executable like in the second case? In other words, is it possible to replace the link to libc.so with a link to libext.so for all symbols defined in the latter?

**Note that interposition via LD_PRELOAD is not what I want. I want to obtain an exectuable which is directly linked to the libraries I need. I underline again that fact the I only have access to the first binary and to the external object I want to "statically" interpose **

like image 605
Martin Avatar asked Aug 19 '13 08:08

Martin


People also ask

Can shared library be statically linked?

You can't statically link a shared library (or dynamically link a static one).

Is a shared object an executable?

There's no difference, aside from the fact that a compiled executable might be linked against a shared object but not against an executable.

What is a statically linked executable?

Statically-linked files are 'locked' to the executable at link time so they never change. A dynamically linked file referenced by an executable can change just by replacing the file on the disk. This allows updates to functionality without having to re-link the code; the loader re-links every time you run it.


2 Answers

It is possible. Learn about shared library interposition:

When a program that uses dynamic libraries is compiled, a list of undefined symbols is included in the binary, along with a list of libraries the program is linked with. There is no correspondence between the symbols and the libraries; the two lists just tell the loader which libraries to load and which symbols need to be resolved. At runtime, each symbol is resolved using the first library that provides it. This means that if we can get a library containing our wrapper functions to load before other libraries, the undefined symbols in the program will be resolved to our wrappers instead of the real functions.

like image 115
Maxim Egorushkin Avatar answered Sep 27 '22 22:09

Maxim Egorushkin


What you ask for is traditionally NOT possible. This has already been discussed here and here.

The crux of your question being -

How to statically link a dynamic shared object?

This cannot be done. The reason being the fact that statically linking a library is effectively the same as taking the compilation results of that library, unpacking them in your current project, and using them as if they were your own objects. *.a files are just archives of a bunch of *.o files with all the info intact within them. On the other hand, dynamic libraries are already linked; the symbol re-location info already being discarded and hence cannot be statically linked into an executable.

However you DO have other alternatives to work around this technical limitation.


So what are your options?

1. Use LD_PRELOAD on target system

Shared library interposition is well described in Maxim's answer.

2. Prepare a pre-linked stand-alone executable

elf-statifier is tool for creating portable, self-contained Linux executables.

It attempts to package together a dynamically-linked executable and all the dynamically-linked libraries of into a single stand-alone executable file. This file can be copied and run on another machine independently.

So now on your development machine, you can set LD_PRELOAD and run the original executable and verify that it works properly. At this point elf-statifier creates a snapshot of the process memory image. This snapshot is saved as an ELF executable, with all the required shared-libraries(incluing your custom libext.so) inside. Hence there is no need to make any modifications (for eg. to LD_PRELOAD) on the target system running the newly generated standalone executable.

However, this approach is not guaranteed to work in all scenarios. This is due to the fact that recent Linux kernels introduced VDSO and ASLR.

A commercial alternative to this is ermine. It can work around VDSO and ASLR limitations.

like image 44
TheCodeArtist Avatar answered Sep 27 '22 21:09

TheCodeArtist