在dlopen-ed库中覆盖malloc / free

时间:2019-01-24 08:42:20

标签: linux malloc libc dlopen

我有一个共享库-plugin.so,由带有标志dlopen的主机程序RTLD_LOCAL编辑,我在该库中定义了自己的内存操作函数:

void *plugin_malloc(size_t size) { /* ... */ }
void plugin_free(void *ptr) { /* ... */ }

我需要用自己的malloc/free替换plugin.so中的所有plugin_malloc/plugin_free调用,我尝试使用GCC的别名属性扩展名:

void *malloc(size_t) __attribute__((alias("plugin_malloc"), used))
void free(void*) __attribute__((alias("plugin_free"), used))

但是,这仅在将库链接到主机程序中时有效,而不能以dlopen方式工作。

我在Linux上使用的是GCC-4.8.5编译器,并且源代码为plugin.so,可以根据需要进行修改,但是我无法修改主机程序 ,并且不仅可以在malloc/free中替换plugin.so,而且在整个程序中也可以替换。

那么,有什么解决办法吗?谢谢。


编辑:我也无权修改宿主程序的启动参数,环境变量,我所能做的只是向拥有宿主程序的人提供plugin.so,并且他们运行主机程序,dlopen我的plugin.so

2 个答案:

答案 0 :(得分:1)

考虑到您在使用-fPIC编译的共享库中提供了一对名为malloc和free的函数(例如,而不是plugin_malloc),那么在调用客户端应用程序时只需要LD_PRELOAD就可以了:

LD_PRELOAD=/path/mymalloc.so executable

或在致电客户之前将其导出:

export LD_PRELOAD=/path/mymalloc.so
executable

更多详细信息:

[更新]

考虑到您不能更改环境,而只能替换动态库,那么您便可以:

  • 找到malloc / free在内存中的位置
  • 将jmp的原始函数输入代码替换为您自己的函数

您的库将需要一个初始化函数来完成此肮脏的工作。检查构造函数属性here。但是,可能不允许替换代码。

另一种可能的探索方法(oit?):如果代码使用glibc,则可以尝试在库中提供__malloc_hook

另一个:在您的库init函数中抓住应用程序控件,再也不要从其返回,然后使用自定义设置再次执行该应用程序。

考虑到您的限制,我暂时无法提出其他任何可能性。

答案 1 :(得分:1)

  

我需要用我自己的plugin_malloc / plugin_free替换plugin.so中的所有malloc / free调用,

这很简单。

假设您有foo.oplugin_malloc.o链接到plugin.so中。 foo.o使用mallocfree,而plugin.o定义plugin_mallocplugin_free

然后:

objcopy --redefine-sym malloc=plugin_malloc --redefine-sym free=plugin_free foo.o foo2.o
gcc -shared -fPIC plugin.o foo2.o -o plugin.so

Voila:malloc中对freefoo.o的所有引用已被替换。享受。

更新

  

如果我调用分配内存的glibc函数,并且需要在我的代码中将其释放,则程序崩溃。例如char * s = strdup(“ hello”);免费;因为strdup调用了glibc的malloc,但后来的免费版本是我的plugin_free

有几种方法,只有其中一些可以满足您的其他限制:

  1. 对于整个程序,您必须用自己的 all mallocfree替换(例如,通过LD_PRELOAD,或通过将malloc实现静态链接到主可执行文件),或
  2. 您必须确保您不要调用希望通过malloc之后通过free分配内存的任何函数,或者
  3. 对于对stdupasprintf等的任何此类调用,当您要取消分配此内存时,必须调用__libc_free而不是plugin_free
  4. plugin_malloc中,用16个额外的字节标头(用于对齐)填充分配的所有内存,以将幻数写入块的开头,然后将指针越过标头返回给调用者。在plugin_free中,检查是否正确对齐,然后检查标题的幻数。如果存在,请从指针中减去16,然后使用plugin_free的其余部分释放内存。如果幻数不存在,则假定指针不是来自plugin_malloc,然后调用__libc_free
  5. plugin_malloc中,跟踪您分配的所有块。在plugin_free中检查该列表,如果指针不在列表中,则使用__libc_free

由于您拥有插件的所有来源,因此解决方案2或3应该都可行,但是显然要求您审核对free的每次调用,以查看内存的来源。

变体4和5不需要进行此类审核,但不会将插件分配的内存与主程序分配的内存完全分开。

别忘了分配内存的其他方法:reallocmemalignposix_memalign