使用动态链接器包装glibc函数 [英] Wrapping a glibc function using the dynamic linker

查看:99
本文介绍了使用动态链接器包装glibc函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过将我的库注入可执行文件来包装GLIBC fstat 函数(可能是其他函数:这只是概念证明).为此,我将库放置在可执行文件的 RPATH 指向名称为 libc.so.6 的位置.

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.

我的库的源代码如下:

#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);
}

我用-version-script 进行编译(以添加符号版本控制),并将其静态链接到libgcc.

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

其中 wrapperlib.map 包含:

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

如果我提供自己的 __ libc_start_main 实现,则不会出现此错误(但它当然会崩溃).

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;
}

为什么在 __ libc_start_main 上而不在 system 上发生重定位错误?

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

(顺便说一句,对 system 的调用确实可以工作,但对 printf 的调用却没有输出.我在这里遗漏了明显的东西吗?)

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

谢谢

使用 LD_DEBUG = all 运行目标将输出以下内容: http://pastebin.com/iVVbwf6n

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

推荐答案

我将可执行文件的 RPATH 指向的库(名称为 libc.so.6 )放置在我的库中.

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

因此,此过程将加载您的库,而不是GLIBC的 libc.so.6 .这肯定不是您想要的,除非您要提供至少整个C标准库的独立实现.这需要您的库提供 libc.so.6 中所有内容的独立实现,或者动态加载真正的 libc .我看到您尝试通过静态链接libgcc(我想您是说使用 -lstatic-libgcc )来实现完整性,但是

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. 那是错误的库.它提供了支持GCC编译的二进制文件的功能,其中可能包括一些C库函数的包装程序或替代程序,但它不提供C库本身.

  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.

即使您静态链接了C库(例如, -lc_nonshared ),通过这种方式获得的库也不会包含可动态加载的符号,您可以通过该符号访问包装的函数.这是静态链接的直接结果.

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.

您的库无论如何都不是独立的,因为它试图包装GLIBC的 fstat()的实现,这对它来说是不可用的.

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

为什么在 __ libc_start_main 而不是 system 上没有重定位错误?

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

__ libc_start_main 上发生重定位错误,因为该函数由glibc的libc.so.6提供,但不是由您的函数提供的,也不是由您的二进制文件本身或由动态链接到您的二进制文件的任何其他库提供的.(请参阅上面的(1))

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)

如果 system printf 函数没有重定位错误,则说明这些不是二进制文件中的外部动态符号,或者它们满足动态链接到您的二进制文件的其他库.( 更新:链接器调试信息显示了这种情况:那些不是外部符号,我的意思是未提供定义的符号;它们由您的库提供,可能是链接libgcc的结果.)细节并不重要,关键是您的策略完全不可行.考虑使用

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.

更新:一种替代方法是为您的共享库提供一个构造函数,该构造函数 dlopen()是真正的 libc.so.6 启用了 RTLD_GLOBAL 标志.这样,您的库本身不必提供完整的C库,但确实需要知道如何查找真实的库.这样肯定可以解决包装函数在包装器中不可用的问题.

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.

这篇关于使用动态链接器包装glibc函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆