Monday 17 June 2013

intercepting libc functions with LD_PRELOAD

What follows is an example of how to intercept uname

// pseudo-handle RTLD_NEXT: find the next occurrence of a function in the search order after the current library. This allows one to provide a wrapper around a function in another shared library.
#ifndef RTLD_NEXT
#    define RTLD_NEXT ((void *) -1L)
#endif

#define REAL_LIBC RTLD_NEXT

// function pointer which will store the location of libc's uname  (ie: the 'real' uname function)
int (*real_uname)(struct utsname *buf) = 0;

static void init (void) __attribute__ ((constructor));
static void init (void)
{
    if(!real_uname)
    {
        real_uname = dlsym(REAL_LIBC, "uname");
        if(!real_uname)
        {
            fprintf(stderr, "missing symbol: uname");
            exit(1);
        }
    }
}

static int do_uname(struct utsname *buf, int (*uname_proc)(struct utsname *buf))
{
    return uname_proc(buf);
}
__attribute__ ((visibility("default"))) int uname(struct utsname *buf)
{
    init(); // we must always call init as constructor may not be called in some cases (such as loading 32bit pthread library)

    int rc = do_uname(buf, real_uname);
    if(!rc)
    {
        // do special processing
    }
    return rc;
}

Compile this into a shared library, and intercept libc's uname by using LD_PRELOAD=libname.so