繁体   English   中英

如何使用 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);
}

请注意此“解决方案”的两件事:

  1. 此代码绕过由(__libc_)dlsym()内部完成的锁定,因此为了使此线程安全,您应该添加一些锁定。
  2. _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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM