I encountered a problem with a piece of software. It seemed it based some calculations on the information it retrieved about a couple of directories. Unfortunately its output changed whenever you made modifications to the OS, which was not desirable. And of course it is a closed source piece of code.

Using strace I could identify which directories it was accessing and which function it was using: lstat64

So looking into a solution for this I quickly came to using LD_PRELOAD to overload the stat call and return modified information. My first attempts failed as the stat call isn’t a published symbol by libc:

nm -D /lib/libc.so.6 | grep stat64 000bbfe0 T __fxstat64 000bbfe0 T __fxstat64 000bc020 T __lxstat64 000bc020 T __lxstat64 000bbfa0 T __xstat64 000bbfa0 T __xstat64

It looks like the stat call is a wrapper for the __ versions of the call. As I found out later, this has to do with compatibility of the structure stat uses.

So, after a few attempts I created a working prototype. Below is an example which intercepts the lstat64 call which ls makes to get information on a file. The code below changes the returned size of the file if it is test.c to 0.

#define _GNU_SOURCE 1

#include <sys/stat.h> #include <dlfcn.h> #include <string.h>

static int (*_lstat)(const int, const char *, struct stat64 *) = NULL;

int __lxstat64(int __ver, __const char *__filename, struct stat64 *__stat_buf) {

    int ret;

    if (!_lstat)
            _lstat = dlsym(RTLD_NEXT, "__lxstat64");

    ret = _lstat(__ver, __filename, __stat_buf);

    if (strcmp(__filename, "test.c")==0)
    {
       __stat_buf->st_size = 0;
    }

    return ret;

}

Compile the code with:

gcc -Wall -fPIC -shared -o test.so test.c -ldl

Now we’ll do a test with and without preloading the library.

Without:

$ ls -al test.* -rw-r--r-- 1 mark mark 443 Jul 20 19:59 test.c -rwxr-xr-x 1 mark mark 4416 Jul 20 19:59 test.so*

With:

$ LD_PRELOAD=./test.so ls -al test.* -rw-r--r-- 1 mark mark 0 Jul 20 19:59 test.c -rwxr-xr-x 1 mark mark 4416 Jul 20 19:59 test.so*

As you can see the library matches the test.c and sets the filesize to zero. Not a very useful example, but a very useful technique.