在 dlopen-ed 库中覆盖 malloc/free
overwrite malloc/free in dlopen-ed library
我有一个共享库 - plugin.so
,它由带有标志 RTLD_LOCAL
的主机程序 dlopen
编辑,我在该库中定义了自己的内存操作函数:
void *plugin_malloc(size_t size) { /* ... */ }
void plugin_free(void *ptr) { /* ... */ }
我需要用我自己的 plugin_malloc/plugin_free
替换 plugin.so
中的所有 malloc/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
的源代码,可以随意修改,但我不能修改宿主程序,不仅plugin.so
而且整个程序都替换malloc/free
也是可以的
那么,有什么解决办法吗?谢谢。
编辑:我也无权修改主机程序的启动参数、环境变量,我能做的只是向拥有的人提供plugin.so
主机程序,他们 运行 主机程序和 dlopen
我的 plugin.so
.
考虑到您在使用 -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。
还有一个:在您的库初始化函数中获取应用程序控制,永远不会从中返回,然后使用您的自定义设置再次执行该应用程序。
目前,考虑到您的限制,我无法得出任何其他可能性。
What I need is to replace ALL malloc/free calls in plugin.so with my own plugin_malloc/plugin_free,
这很容易做到。
假设您有 foo.o
和 plugin_malloc.o
链接到 plugin.so
。 foo.o
使用 malloc
和 free
,而 plugin.o
定义 plugin_malloc
和 plugin_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
瞧:foo.o
中对 malloc
和 free
的所有引用都已被替换。享受。
更新:
if I call a glibc function which allocates memory and needs to be freed in my code, the program crashes. e.g. char *s = strdup("hello"); free(s); because strdup calls glibc's malloc, but the later free is my plugin_free
有几种方法,其中只有一些满足您的其他限制条件:
- 您必须将 所有
malloc
s 和 free
s 替换为您自己的 entire 程序 (例如,通过 LD_PRELOAD
,或通过将 malloc
实现静态链接到主可执行文件中),或
- 您必须确保您不会调用任何您希望稍后
free
通过malloc
分配内存的函数,或者
- 对于
stdup
或 asprintf
等的任何此类调用,当您想要释放此内存时,您必须调用 __libc_free
而不是 plugin_free
,或者
- 在
plugin_malloc
中,用16个额外的字节填充你分配的所有内存header(用于对齐)将幻数写入块的开头,并且return一个指针过去header 给来电者。在 plugin_free
中检查对齐是否正确,然后检查 header 中的幻数。如果它在那里,从指针中减去 16 并使用 plugin_free
的其余部分来释放内存。如果幻数不存在,假设指针不是来自 plugin_malloc
,而是调用 __libc_free
。
- 在
plugin_malloc
中跟踪您曾经分配的所有块。在 plugin_free
中检查该列表,如果指针不在列表中则使用 __libc_free
。
由于您拥有插件的所有资源,因此解决方案 2 或 3 应该可行,但显然需要您审核对 free
的每次调用以查看内存来自何处。
变体 4 和 5 不需要这样的审计,但没有将插件分配的内存与主程序分配的内存完全分开。
不要忘记其他分配内存的方法:realloc
、memalign
、posix_memalign
等
我有一个共享库 - plugin.so
,它由带有标志 RTLD_LOCAL
的主机程序 dlopen
编辑,我在该库中定义了自己的内存操作函数:
void *plugin_malloc(size_t size) { /* ... */ }
void plugin_free(void *ptr) { /* ... */ }
我需要用我自己的 plugin_malloc/plugin_free
替换 plugin.so
中的所有 malloc/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
的源代码,可以随意修改,但我不能修改宿主程序,不仅plugin.so
而且整个程序都替换malloc/free
也是可以的
那么,有什么解决办法吗?谢谢。
编辑:我也无权修改主机程序的启动参数、环境变量,我能做的只是向拥有的人提供plugin.so
主机程序,他们 运行 主机程序和 dlopen
我的 plugin.so
.
考虑到您在使用 -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。
还有一个:在您的库初始化函数中获取应用程序控制,永远不会从中返回,然后使用您的自定义设置再次执行该应用程序。
目前,考虑到您的限制,我无法得出任何其他可能性。
What I need is to replace ALL malloc/free calls in plugin.so with my own plugin_malloc/plugin_free,
这很容易做到。
假设您有 foo.o
和 plugin_malloc.o
链接到 plugin.so
。 foo.o
使用 malloc
和 free
,而 plugin.o
定义 plugin_malloc
和 plugin_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
瞧:foo.o
中对 malloc
和 free
的所有引用都已被替换。享受。
更新:
if I call a glibc function which allocates memory and needs to be freed in my code, the program crashes. e.g. char *s = strdup("hello"); free(s); because strdup calls glibc's malloc, but the later free is my plugin_free
有几种方法,其中只有一些满足您的其他限制条件:
- 您必须将 所有
malloc
s 和free
s 替换为您自己的 entire 程序 (例如,通过LD_PRELOAD
,或通过将malloc
实现静态链接到主可执行文件中),或 - 您必须确保您不会调用任何您希望稍后
free
通过malloc
分配内存的函数,或者 - 对于
stdup
或asprintf
等的任何此类调用,当您想要释放此内存时,您必须调用__libc_free
而不是plugin_free
,或者 - 在
plugin_malloc
中,用16个额外的字节填充你分配的所有内存header(用于对齐)将幻数写入块的开头,并且return一个指针过去header 给来电者。在plugin_free
中检查对齐是否正确,然后检查 header 中的幻数。如果它在那里,从指针中减去 16 并使用plugin_free
的其余部分来释放内存。如果幻数不存在,假设指针不是来自plugin_malloc
,而是调用__libc_free
。 - 在
plugin_malloc
中跟踪您曾经分配的所有块。在plugin_free
中检查该列表,如果指针不在列表中则使用__libc_free
。
由于您拥有插件的所有资源,因此解决方案 2 或 3 应该可行,但显然需要您审核对 free
的每次调用以查看内存来自何处。
变体 4 和 5 不需要这样的审计,但没有将插件分配的内存与主程序分配的内存完全分开。
不要忘记其他分配内存的方法:realloc
、memalign
、posix_memalign
等