Wrapping a glibc function using the dynamic linker

早过忘川 提交于 2021-01-27 07:58:08

问题


I am trying to wrap the GLIBC fstat function (it could be any other: it is just a proof of concept) by injecting my library to an executable. I do this by placing my library where the executable's RPATH is pointing with the name libc.so.6.

The source code of my library is the one below:

#define _GNU_SOURCE

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dlfcn.h>



int fstat(int fd, struct stat *buf){

        typeof(fstat) *old_fstat;

        // Try with a printf...

        printf("HOOT! fstat wrapped!");

        old_fstat = dlsym(RTLD_NEXT, "fstat");
        return (*old_fstat)(fd, buf);
}

I compile it with --version-script (to add symbol versioning) and statically link it to libgcc.

gcc -Wall -fPIC -c -o wrapperlib.o wrapperlib.c 
gcc -shared -static-libgcc -fPIC -Wl,-soname -Wl,libc.so.6 -Wl,--version-script=wrapperlib.map,-Bstatic -o libc.so.6 wrapperlib.o

With wrapperlib.map containing:

GLIBC_2.0 {
};

When I execute the target program my library gets loaded but I get the following error:

./target: relocation error: ./target: symbol __libc_start_main, version GLIBC_2.0 not defined in file libc.so.6 with link time reference

If I provide my own implementation of __libc_start_main I don't get this error (but it crashes, of course).

int __libc_start_main(int (*main) (int, char **, char **), int argc, char *argv, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void *stack_end) {
        system("echo I am in __libc_start_main");
        printf("printf: I am in __libc_start_main");
        fflush(stdin);
    return 0;
}

Why is there a relocation error on __libc_start_main and not on system?

(By the way, the call to the system does work but the call to printf produces no output. Am I missing something obvious here?)

Thank you

Edit: Running target with LD_DEBUG=all outputs this: http://pastebin.com/iVVbwf6n


回答1:


I [place] my library where the executable's RPATH is pointing with the name libc.so.6.

And therefore the process loads your library instead of GLIBC's libc.so.6. That is surely not what you want unless you're providing an independent implementation of at least the entire C standard library. That requires your library to provide an independent implementation of everything in libc.so.6, or else to dynamically load the real libc. I see that you attempt to attain completeness by statically linking libgcc (I guess you mean using -lstatic-libgcc), but

  1. that's the wrong library. It provides functions to support GCC-compiled binaries, which may include wrappers or alternatives for some C-library functions, but it does not provide the C library itself.

  2. even if you linked the C library statically (e.g. -lc_nonshared), the library you get that way will not include a dynamically loadable symbol by which you can access the wrapped function. That's a direct consequence of the static linking.

  3. your library is anyway not independent because it tries to wrap GLIBC's implementation of fstat(), which is unavailable to it.

Why is there a relocation error on __libc_start_main and not on system?

There is a relocation error on __libc_start_main because that function is provided by the glibc's libc.so.6, but not by yours, nor by your binary itself or any other library dynamically linked to your binary. (See (1) above)

If there is no relocation error for the system or printf functions, then it follows that either those are not external dynamic symbols in your binary, or they are satisfied by some other library dynamically linked to your binary. (Update: the linker debug information shows the former to be the case: those are not external symbols, by which I meant symbols for which no definition is provided; they are provided by your library, presumably as a result of linking in libgcc.) The details don't really matter, as the point is that your strategy is totally unworkable. Consider using LD_PRELOAD instead.

Update: an alternative might be to give your shared library a constructor function that dlopen()s the real libc.so.6 with flag RTLD_GLOBAL enabled. This way, your library does not have to provide a complete C library itself, but it does need to know how to find the real library. That will certainly solve the problem of the wrapped function being unavailable in the wrapper.



来源:https://stackoverflow.com/questions/41145062/wrapping-a-glibc-function-using-the-dynamic-linker

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!