[英]Overriding 'free' or 'delete' using LD_PRELOAD & dlsym()
[英]How can I intercept dlsym calls using LD_PRELOAD?
我想拦截应用程序对 dlsym 的调用。 我尝试在 .so 中声明,以便我预加载 dlsym ,并使用 dlsym 本身来获取它的真实地址,但是由于很明显的原因,这不起作用。
有没有比获取进程的内存映射并使用 libelf 在加载的 libdl.so 中找到 dlsym 的真实位置更容易的方法?
我在 hdante 的回答中偶然发现了与评论者相同的问题:调用__libc_dlsym()
直接因段错误而崩溃。 在阅读了一些 glibc 源代码后,我想出了以下 hack 作为解决方法:
extern void *_dl_sym(void *, const char *, void *);
extern void *dlsym(void *handle, const char *name)
{
/* my target binary is even asking for dlsym() via dlsym()... */
if (!strcmp(name,"dlsym"))
return (void*)dlsym;
return _dl_sym(handle, name, dlsym);
}
请注意此“解决方案”的两件事:
(__libc_)dlsym()
内部完成的锁定,因此为了使此线程安全,您应该添加一些锁定。_dl_sym()
的第三个参数是调用者的地址,glibc 似乎通过堆栈展开来重建这个值,但我只是使用函数本身的地址。 调用者地址在内部用于查找调用者所在的链接映射,以使RTLD_NEXT
类的RTLD_NEXT
正确(并且,使用 NULL 作为第三个参数将使调用在使用RTLD_NEXT
时失败并出现错误)。 但是,我没有看过 glibc 的 unwindind 功能,所以我不能 100% 确定上面的代码会做正确的事情,而且它可能只是偶然地工作...... 到目前为止提出的解决方案有一些明显的缺点: _dl_sym()
dlsym()
在某些情况下与预期的dlsym()
行为完全不同。 例如,尝试解析一个不存在的符号会退出程序,而不仅仅是返回 NULL。 要解决这个问题,可以使用_dl_sym()
来获取指向原始dlsym()
的指针并将其用于其他所有内容(例如在“标准” LD_PRELOAD
挂钩方法中,根本不挂钩dlsym
):
extern void *_dl_sym(void *, const char *, void *);
extern void *dlsym(void *handle, const char *name)
{
static void * (*real_dlsym)(void *, const char *)=NULL;
if (real_dlsym == NULL)
real_dlsym=_dl_sym(RTLD_NEXT, "dlsym", dlsym);
/* my target binary is even asking for dlsym() via dlsym()... */
if (!strcmp(name,"dlsym"))
return (void*)dlsym;
return real_dlsym(handle,name);
}
http://www.linuxforu.com/2011/08/lets-hook-a-library-function/
从文中:
当您需要在钩子中调用 __libc_dlsym (句柄,符号)时,请注意自身调用 dlsym() 的函数。
extern void *__libc_dlsym (void *, const char *);
void *dlsym(void *handle, const char *symbol)
{
printf("Ha Ha...dlsym() Hooked\n");
void* result = __libc_dlsym(handle, symbol); /* now, this will call dlsym() library function */
return result;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.