Recently I had a chance to play with LD_PRELOAD
for a bit, due to our recent
Huge Refactor (tm) at Nodejitsu. LD_PRELOAD
environment variable is a way of
loading a library before any other libraries are loaded.
For example, let’s write this short program in C:
Its output is obvious:
$ gcc puts.c -o puts
$ ./puts
Hello, world!
Now, as I mentioned before, with LD_PRELOAD
we can force our library to be
loaded before other libraries. This also affects libc
. That means that we can
override the puts()
function
Let’s compile this little library and try to override puts
from libc
:
Thanks to dlsym(RTLD_NEXT, "puts")
, we’re able to extract the original puts
function and call it with different arguments. RTLD_NEXT
is a pseudo-handle
which makes linker search for occurences of symbol in libraries loaded after
current library.
First problem we’re going to run into is the difference between how Mac OS X and other UNIX operating systems work.
To compile this library on Mac OS X execute:
To compile it on other operating systems, use:
Now that we compiled the library, let’s try overriding our puts
call.
On Mac OS X:
$ export DYLD_FORCE_FLAT_NAMESPACE=1
$ export DYLD_INSERT_LIBRARIES=./puts-override.dylib
$ ./puts
On other operating systems:
$ export LD_PRELOAD=./puts-override.so
$ ./puts
Hello, puts!
Now, the difference between compilation and usage come from the fact that Mac OS X uses a different linker than other systems. You can read more about OS X’s linker on its manual page.
That’s it for this blog post. If you have problems getting those instructions to work, shoot me a line!