如何使用LD_PRELOAD拦截dlsym调用?

时间:2013-03-24 13:26:56

标签: c++ c intercept ld-preload dlsym

我想拦截应用程序对dlsym的调用,我已经尝试在.so中声明我正在预加载dlsym,并使用dlsym本身来获取它的真实地址,但是由于非常明显的原因不起作用。 / p>

有没有比采用进程'内存映射更简单的方法,并使用libelf在加载的libdl.so中找到dlsym的真实位置?

2 个答案:

答案 0 :(得分:4)

我和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()的thrid参数是调用者的地址,glibc似乎通过堆栈展开来重构这个值,但我只是使用函数本身的地址。调用者地址在内部用于查找调用者所在的链接映射以使RTLD_NEXT之类的东西正确(并且,使用NULL作为thrid参数将使调用失败并在使用RTLD_NEXT时出错)。但是,我没有看过glibc的unwindind功能,所以我不是百分之百确定上面的代码会做正确的事情,而且它可能只是偶然的机会......
  3. 到目前为止提出的解决方案存在一些明显的缺点:在某些情况下,_dl_sym()的行为与预期的dlsym()完全不同。例如,尝试解析不存在的符号会退出程序而不是仅返回NULL。要解决这个问题,可以使用_dl_sym()来获取指向原始dlsym()的指针并将其用于其他所有内容(例如“标准”LD_PRELOAD挂钩approch而不挂钩{{总共1}}:

    dlsym

答案 1 :(得分:0)

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;
}