Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change library load order at run time (like LD_PRELOAD but during execution)

How do I change the library a function loads from during run time?

For example, say I want to replace the standard printf function with something new, I can write my own version and compile it into a shared library, then put "LD_PRELOAD=/my/library.so" in the environment before running my executable.

But let's say that instead, I want to change that linkage from within the program itself. Surely that must be possible... right?

EDIT
And no, the following doesn't work (but if you can tell me how to MAKE it work, then that would be sufficient).

void* mylib = dlopen("/path/to/library.so",RTLD_NOW);
printf = dlsym(mylib,"printf");
like image 323
tylerl Avatar asked Jun 18 '10 06:06

tylerl


2 Answers

AFAIK, that is not possible. The general rule is that if the same symbol appears in two libraries, ld.so will favor the library that was loaded first. LD_PRELOAD works by making sure the specified libraries are loaded before any implicitly loaded libraries.

So once execution has started, all implicitly loaded libraries will have been loaded and therefore it's too late to load your library before them.

like image 118
R Samuel Klatchko Avatar answered Oct 19 '22 07:10

R Samuel Klatchko


There is no clean solution but it is possible. I see two options:

  1. Overwrite printf function prolog with jump to your replacement function.

    It is quite popular solution for function hooking in MS Windows. You can find examples of function hooking by code rewriting in Google.

  2. Rewrite ELF relocation/linkage tables.

    See this article on codeproject that does almost exactly what you are asking but only in a scope of dlopen()'ed modules. In your case you want to also edit your main (typically non-PIC) module. I didn't try it, but maybe its as simple as calling provided code with:

    void* handle = dlopen(NULL, RTLD_LAZY);
    void* original;
    original = elf_hook(argv[0], LIBRARY_ADDRESS_BY_HANDLE(handle), printf, my_printf);
    

    If that fails you'll have to read source of your dynamic linker to figure out what needs to be adapted.

like image 39
Marcin Wisnicki Avatar answered Oct 19 '22 05:10

Marcin Wisnicki