copyright 1998-2018 by Mark Verboom
ipv6 ready RSS Feed Switch to English

Ga terug naar Nieuws

Overloading library calls

Naar blog index

Wednesday, 20 July, 2011

Overloading library calls

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.