如何重写标准的libc函数? [英] How to override standard libc functions?

查看:181
本文介绍了如何重写标准的libc函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,如果我想重写malloc(),什么是最好的方法?

For example, if I want to override malloc(), what's the best way to do it?

目前我所知道的最简单的方法是:

Currently the simplest way I know of is:

malloc.h

#include <stdlib.h>
#define malloc my_malloc
void* my_malloc (size_t size);

foobar.c

#include "malloc.h"

void foobar(void)
{
    void* leak = malloc(1024);
}

这种方法的问题是我们现在必须使用"malloc.h",并且永远不能使用"stdlib.h".有没有解决的办法?我对导入第3方库特别感兴趣,而不需要对其进行任何修改,而是强迫它们调用我的自定义libc函数(如malloc).

The problem with this approach is that we now have to use "malloc.h" and can never use "stdlib.h". Is there a way around this? I'm particularly interested in importing 3rd party libraries without modifying them at all, but forcing them into calling my custom libc functions (like malloc).

推荐答案

简短的答案是您可能想使用LD_PRELOAD技巧:

The short answer is you probably want to use the LD_PRELOAD trick: What is the LD_PRELOAD trick?

该方法基本上是在运行时在加载任何其他共享库之前在运行时插入您自己的自定义共享库,并导出要覆盖的函数,例如malloc().到其他共享库加载时,您的符号已经存在,并且在解析从其他库对该符号名称的调用时会获得首选项.在您的malloc()包装程序/替换文件中,您甚至可以选择调用下一个malloc符号,该符号通常是实际的libc符号.

That approach basically inserts your own custom shared library on runtime before any other shared library is loaded, exporting the functions you want to override, such as malloc(). By the time the other shared libraries are loaded your symbol is already there and gets preference when resolving calls to that symbol name from other libraries. From within your malloc() wrapper/replacement you can even chose to call the next malloc symbol, which typically would be the actual libc symbol.

此博客文章提供了有关此方法的很多综合信息:

This blog post has a lot of comprehensive information about this method:

http://samanbarghi.com/blog/2014/09/05/how-to-wrap-a-system-call-libc-function-in-linux/

请注意,该示例重写了libc的write()和puts()函数,但相同的逻辑适用于malloc():

Note that example is overriding libc's write() and puts() functions, but the same logic applies for malloc():

LD_PRELOAD允许先加载共享库,然后再加载其他任何库.因此,我所要做的就是编写一个覆盖write和puts函数的共享库.如果包装这些函数,则需要一种方法来调用实际函数以执行系统调用. dlsym就是为我们做到这一点[man 3 dlsym]:>函数dlsym()接受dlopen()返回的动态库和以空值结尾的符号名称的句柄",返回将该符号加载到内存中的地址.如果未找到符号,则在指定的库中,或在加载该库时由dlopen()自动加载的任何库中,dlsym()返回NULL…

LD_PRELOAD allows a shared library to be loaded before any other libraries. So all I need to do is to write a shared library that overrides write and puts functions. If we wrap these functions, we need a way to call the real functions to perform the system call. dlsym just do that for us [man 3 dlsym]: > The function dlsym() takes a "handle" of a dynamic library returned by dlopen() and the null-terminated symbol name, returning the address where that symbol is loaded into memory. If the symbol is not found, in the specified library or any of the libraries that were automatically loaded by dlopen() when that library was loaded, dlsym() returns NULL…

因此在包装函数内部,我们可以使用dlsym获取内存中相关符号的地址,然后调用glibc函数.另一种方法可以直接调用syscall,这两种方法都可以使用.

So inside the wrapper function we can use dlsym to get the address of the related symbol in memory and call the glibc function. Another approach can be calling the syscall directly, both approaches will work.

该博客文章还描述了一个我不知道的编译时方法,该方法涉及将链接器标志传递给ld,-wrap":

That blog post also describes a compile-time method I did not know about that involves passing a linker flag to ld, "--wrap":

包装函数的另一种方法是在链接时使用链接器. GNU链接器提供了用于包装符号功能的选项[man 1 ld]:>为符号使用包装功能.任何未定义的符号引用都将解析为"__wrap_symbol".任何对"__real_symbol"的未定义引用都将解析为符号.

Another way of wrapping functions is by using linker at the link time. GNU linker provides an option to wrap a function for a symbol [man 1 ld]: > 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.

关于LD_PRELOAD的一个方便的事情是,它可能允许您更改生产应用程序上的malloc()实现以进行快速测试,甚至允许用户选择(在某些服务器应用程序中是这样做的)使用哪种实现.例如," tcmalloc "库可轻松插入到应用程序中以评估性能在线程密集的应用程序中获益(tcmalloc的性能往往比libc的malloc实现好得多).

The handy thing about LD_PRELOAD is that might allow you to change the malloc() implementation on production applications for quick testing, or even allow the user to select (I do this in some server applications) which implementation to use. The 'tcmalloc' library for example can be easily inserted into an application to evaluate performance gains in heavily threaded applications (where tcmalloc tends to perform a lot better than libc's malloc implementation).

最后,如果您使用的是Windows,请尝试以下操作:等效于Windows的LD_PRELOAD来预加载共享库

Finally if you're on Windows, perhaps try this: LD_PRELOAD equivalent for Windows to preload shared libraries

这篇关于如何重写标准的libc函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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