开发者

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

开发者 https://www.devze.com 2023-01-03 17:52 出处:网络
How do I change the library a function loads from during run time? For example, say I want to replace the standard printf开发者_如何学JAVA function with something new, I can write my own version and

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

For example, say I want to replace the standard printf开发者_如何学JAVA 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");


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.


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.


It should be said that trying to replace functions from the libc in your application has undefined behavior as per ISO C/POSIX, regardless of whether you do it statically or dynamically. It may work (and largely will work on GNU/Linux), but it's unwise to rely on it working. If you just want to use the name "printf" but have it do something nonstandard in your program, the best way to do this is to #undef printf and #define printf my_printf AFTER including any system headers. This way you don't interfere with any internal use of the function by libraries you're using...and your implementation of my_printf can even call the system printf if/when it needs to.

On the other hand, if your goal is to interfere with what libraries are doing, somewhere down the line you're probably going to run into compatibility issues. A better approach would probably be figuring out why the library won't do what you want without redefining the functions it uses, patching it, and submitting patches upstream if they're appropriate.


You can't change that. In general *NIX linking concept (or rather lack of concept) symbol is picked from first object where it is found. (Except for oddball AIX which works more like OS/2 by default.)

Programmatically you can always try dlsym(RTLD_DEFAULT) and dlsym(RTLD_NEXT). man dlsym for more. Though it gets out of hand quite quickly. Why is rarely used.


there is an environment variable LD_LIBRARY_PATH where the linker searches for shred libraries, prepend your path to LD_LIBRARY_PATH, i hope that would work


Store the dlsym() result in a lookup table (array, hash table, etc). Then #undef print and #define print to use your lookup table version.

0

精彩评论

暂无评论...
验证码 换一张
取 消