如何在 Linux 上重新实现(或包装)系统调用函数?

发布于 2024-09-18 07:38:06 字数 494 浏览 14 评论 0原文

假设我想完全接管 open() 系统调用,也许要包装实际的系统调用并执行一些日志记录。 一种方法这是使用 LD_PRELOAD 加载一个(用户制作的)共享对象库,该库接管 open() 入口点。

然后,用户编写的 open() 例程通过dlsym()调用并获取指向 glibc 函数 open() 的指针。

然而,上面提出的解决方案是动态解决方案。假设我想静态链接我自己的 open() 包装器。我该怎么做呢?我猜想机制是一样的,但我也猜想用户定义的 open() 和 libc open() 之间会存在符号冲突。

请分享任何其他技术来实现相同的目标。

Suppose I want to completely take over the open() system call, maybe to wrap the actual syscall and perform some logging. One way to do this is to use LD_PRELOAD to load a (user-made) shared object library that takes over the open() entry point.

The user-made open() routine then obtains the pointer to the glibc function open() by dlsym()ing it, and calling it.

The solution proposed above is a dynamic solution, however. Suppose I want to link my own open() wrapper statically. How would I do it? I guess the mechanism is the same, but I also guess there will be a symbol clash between the user-defined open() and the libc open().

Please share any other techniques to achieve the same goal.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

数理化全能战士 2024-09-25 07:38:06

您可以使用ld提供的换行功能。来自man ld

--wrap symbol 对符号使用包装函数。任何未定义的引用
symbol 将解析为 __wrap_symbol

__real_symbol 的任何未定义引用都将解析为 symbol

因此,您只需为包装函数使用前缀 __wrap_ ,并在想要调用实际函数时使用 __real_ 。一个简单的示例是:

malloc_wrapper.c

#include <stdio.h>
void *__real_malloc (size_t);

/* This function wraps the real malloc */
void * __wrap_malloc (size_t size)
{
    void *lptr = __real_malloc(size);
    printf("Malloc: %lu bytes @%p\n", size, lptr);
    return lptr;
}

测试应用程序 testapp.c

#include <stdio.h>
#include <stdlib.h>
int main()
{
    free(malloc(1024)); // malloc will resolve to __wrap_malloc
    return 0;
}

然后编译应用程序:

gcc -c malloc_wrapper.c
gcc -c testapp.c
gcc -Wl,-wrap,malloc testapp.o malloc_wrapper.o -o testapp

生成的应用程序的输出将是:

$ ./testapp
Malloc: 1024 bytes @0x20d8010

You can use the wrap feature provided by ld. From man ld:

--wrap symbol Use a wrapper function for symbol. Any undefined reference to
symbol will be resolved to __wrap_symbol.

Any undefined reference to __real_symbol will be resolved to symbol.

So you just have to use the prefix __wrap_ for your wrapper function and __real_ when you want to call the real function. A simple example is:

malloc_wrapper.c:

#include <stdio.h>
void *__real_malloc (size_t);

/* This function wraps the real malloc */
void * __wrap_malloc (size_t size)
{
    void *lptr = __real_malloc(size);
    printf("Malloc: %lu bytes @%p\n", size, lptr);
    return lptr;
}

Test application testapp.c:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    free(malloc(1024)); // malloc will resolve to __wrap_malloc
    return 0;
}

Then compile the application:

gcc -c malloc_wrapper.c
gcc -c testapp.c
gcc -Wl,-wrap,malloc testapp.o malloc_wrapper.o -o testapp

The output of the resulting application will be:

$ ./testapp
Malloc: 1024 bytes @0x20d8010
枫林﹌晚霞¤ 2024-09-25 07:38:06

链接器按照您在命令行上列出符号的顺序解析符号,因此如果您在标准库之前列出您的库,则您将具有优先权。对于 gcc,您需要指定

gcc <BLAH> -nodefaultlibs <BLAH BLAH> -lYOUR_LIB <OTHER_LIBS>

这样您的库将首先被搜索和找到。

Symbols are resolved by the linker in the order you list them on the command line so if you listed your library before the standard library you'd have precidence. For gcc you'd need to specify

gcc <BLAH> -nodefaultlibs <BLAH BLAH> -lYOUR_LIB <OTHER_LIBS>

This way your libraries would be searched and found first.

夜深人未静 2024-09-25 07:38:06

对于 linux 和 GNU libc,该库内置了对拦截和重新实现库中任何函数的支持。

如果您定义自己的任何 libc 函数版本,并将其链接在 libc 之前(因此将其作为可执行文件的一部分,或者在链接命令上的 -lc 之前链接的库中,甚至使用 LD_PRELOAD 加载,如果libc 是动态链接的),它将被调用而不是 libc 版本(甚至调用 libc 本身的其他函数)。然后,您可以使用 __libc_ 前缀调用该函数,以获取库中的实际版本(尽管您需要自己声明该符号。)例如:

       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

       extern int __libc_open(const char *pathname, int flags, mode_t mode);

       int open(const char *pathname, int flags, mode_t mode) {
           return __libc_open(pathname, flags, mode);
       }

For linux and GNU libc, the library has built-in support for intercepting and reimplementing any function in the library.

If you define you own version of ANY libc function, and link it before libc (so have it part of your executable, or in a library linked before -lc on the link command or even loaded with LD_PRELOAD if libc is dynamically linke), it will be called instead of the libc version (even calls in other function in libc itself). You can then call the function with a __libc_ prefix to get the actual version in the library (though you will need to declare that symbol yourself.) For example:

       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

       extern int __libc_open(const char *pathname, int flags, mode_t mode);

       int open(const char *pathname, int flags, mode_t mode) {
           return __libc_open(pathname, flags, mode);
       }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文