为什么LD_PRELOAD技巧不适用于librt?

时间:2013-11-01 07:55:05

标签: c linux gcc linker ld

我试图将LD_PRELOAD技巧应用于某些专有二进制文件。我之前做过类似的事情,但这次没有运气。我试图拦截的调用是timer_settime()。

Strace清楚地表明timer_settime()是由二进制文件调用的:

[pid 30500] timer_settime(0x2, 0, {it_interval={30, 0}, it_value={30, 0}}, {it_interval={0, 0}, it_value={0, 0}}) = 0

它以不同的时间间隔被多次调用。我想以30秒的间隔完全捕捉上面的那个。

这是我的代码,timerwrap.c:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <time.h>
#include <stdio.h>
int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value)
{
    printf("Enter timer.\n");

    if((new_value->it_interval).tv_sec == 30) {
        printf("Catched!\n");
        return 0;
    }

    int (*real_timer_settime)(timer_t, int, const struct itimerspec *, struct itimerspec *);
    real_timer_settime = dlsym(RTLD_NEXT, "timer_settime");
    return real_timer_settime(timerid, flags, new_value, old_value);
}

gcc命令行:

gcc -Wall -g -shared -fPIC  -o timerwrap.so timerwrap.c -ldl -lrt

运行程序:

export LD_PRELOAD=/home/Work/C/timerwrap.so
./the_program

但它未能拦截电话。

我用LD_DEBUG = all再次运行它以进一步调查。事实证明,对于许多其他符号,查找了timerwrap.so,例如dlsym的查找路径在调试输出中如下所示:

2006:   symbol=dlsym;  lookup in file=/.../the_program [0]
2006:   symbol=dlsym;  lookup in file=/home/Work/C/timerwrap.so [0]
2006:   symbol=dlsym;  lookup in file=./lib/libssl.so.6 [0]
2006:   symbol=dlsym;  lookup in file=/lib/i686/cmov/libdl.so.2 [0]
2006:   binding file /.../the_program [0] to /lib/i686/cmov/libdl.so.2 [0]: normal symbol `dlsym' [GLIBC_2.0]

但是,对于timer_settime,查找只需要一步,直接进入/usr/lib/librt.so,绕过timerwrap.so:

2006:   symbol=timer_settime;  lookup in file=/usr/lib/librt.so [0]
2006:   binding file /usr/lib/librt.so [0] to /usr/lib/librt.so [0]: normal symbol `timer_settime'

那么这里发生了什么?为什么librt.so很特别?有什么想法吗?

这是我的第一个问题。在此先感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

一个简单的示例程序向我展示了一切都按预期工作。

您尝试使用的应用程序可能会通过timer_settime加载dlsym

执行dlsym(dlopen("librt.so"), "timer_settime")

解决这个问题不应该那么难,只需在源代码中添加以下内容:

extern void *_dl_sym (void *handle, const char *name, void *who);
void *dlsym(void *handle, const char *symbol) 
{ 
        printf("Enter dlsym.\n");
        void* result = _dl_sym(handle, symbol, 0); // the replacement we are going to use 
        if ((handle != RTLD_NEXT) || (handle != RTLD_DEFAULT))
        if(!strcmp(symbol, "timer_settime")) { 
               printf("Return our timer_settime");
               return timer_settime;
        } 
        return result; 
}