mips42

"DED n. : Dark-Emitting Diode, i.e., a burned-out LED, mainly used as a power-off indicator."

Intercepting with LD_PRELOAD

Introduction

Hi there :)
In this (short) essay we will be studying how to intercept/override library procedure calls using the LD_PRELOAD environment variable and our crafted library. It is a really simple thing but it can come handy.

Be warned: I know what some of you will be thinking by now, well let me point out you cannot use this technique with setuid or setgid binaries, unless...
Furthermore, but it should be obvious, this technique can only be used on dynamically linked executables.

Tools

We will need just gcc, which should be available in every respectable linux distro. Shouldn't it be there, download the necessary packages, or throw the distro's cd/dvd out of the window (do not do that from a plane!).

Preliminary reading

If you need some background information, Wikipedia's page about software libraries will prove to be quite interesting.

Theory

First, let us see what the manual has about this: $ man ls.so
[...]
LD_PRELOAD
  A whitespace-separated list of additional, user-specified, ELF
  shared libraries to be loaded before all others. This can be
  used to selectively override functions in other shared
  libraries.
[...]
Simply put, this means that when an application run with LD_PRELOAD calls function X, if there is a function named X in the libraries we provided it will be called, if not, X will be searched for the usual way.

Let us put that into practice. Suppose we have an executable named target in the current directory. Usually we would run it like this: $ ./target But this time we need to give an environment variable a certain value (in this example we will be assigning value to VARIABLE), and we just need this assignment to stand while target runs. We can accomplish that like this: $ VARIABLE=value ./target Finally, in order to let LD_PRELOAD load our libfake.so library, which is also in the current directory, we will use this command: $ LD_PRELOAD=./libfake.so ./target

Practice

What we learned until now should be enough, but let us present a simple example to further clarify this. Suppose our target has been built with dynamical linking from the following source code: // target.c
#include <stdio.h>
#include <unistd.h>

int main() {
  printf( "user id: %d\n", getuid() );
  return 0;
}
As you can see, everything is very simple. This program prints the user id of the user who run it. If I run target on my system I get: $ ./target
user id: 1000
1000 is a typical unprivileged user id. Our mission would be to make the program print 0 for our user id, which would normally happen if it was run by root.

To accomplish that, let us create a simple library implementing a version of getuid() that always returns 0: // libfake.c

int getuid() {
  return 0;
}
As you can see, everything is still very simple. Let us build this source file as a shared library, with this command: $ gcc -shared libfake.c -o libfake.so Now we are ready to assign the location of our libfake.so library to LD_PRELOAD. If it is in the current directory too, here's how to run it and what happens: $ LD_PRELOAD=./libfake.so ./target
user id: 0
Well, I guess we made it, a piece of cake :)

Final words

Uh, I left an "unless..." statement hanging in the air. Well, here's how it should have ended:
... the library to preload is located in the standard search paths (e.g. /usr/lib) and has the setuid bit set.
That said, have fun.
If you want to talk, head on to the contact page.
See you next essay... bye.
Top
This web site is written in XHTML 1.0 Strict and CSS 2.
It is licensed under a Creative Commons Attribution-Noncommercial 3.0 License.