Zoom Icon

Intercepting with LD PRELOAD

From UIC


Uic translate.png
Questa pagina esiste anche in Italiano Flag it.gif.

Intercepting with LD_PRELOAD

Contents


Intercepting with LD PRELOAD
Author: Bender0
Email: Mips-email.png
Website: http://mips42.altervista.org/
Date: 10/08/2007 (dd/mm/yyyy)
Level: Some skills are required
Language: English Flag English.gif
Comments: Simple and handy.



Introduction

Hi there :)
In this (short) essay we'll be studying how to intercept/override library procedure calls using the LD_PRELOAD environment variable and our crafted library. It's 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'll 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 (don't to that from a plane!).


Links and References

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


Essay

Theory

First, let's 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's 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'll 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'll 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 unpriviledged 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's 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're ready to assign the location of our libfake.so library to LD_PRELOAD. If it's 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 :)

Uh, I left an "unless..." statement hanging in the air. Well, here's how it should've 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 know how to do the same thing with statically linked executables, I think you will like this essay.


Final Notes

As far as I know, this is the first essay in the linux section. Let's just hope it's not the last one :)
As always, thanks to all the people from UIC :)
See you next essay... bye.


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.