LD PRELOAD notes

From Noah.org
Revision as of 02:27, 27 March 2014 by Root (talk | contribs)
Jump to navigationJump to search

See also

The Snoopy Logger is a tool that will log every exec system call (and its many siblings). It can also be setup just to log a single command. For example this will log a bash session LD_PRELOAD=/lib/snoopy.so bash. This would log every command entered into bash, except for the hell built-in commands. The log output usually ends up in /var/log/auth.log or /var/log/syslog depending on how your syslog is configured. You can also log the entire system this way doing the following echo "/lib/snoopy.so" > /etc/ld.so.preload... Note that even after you remove snoopy.so from /etc/ls.so.preload you may still see data logged to this file. The because there must be a process that was started before snoopy.so was disabled, so any process like this will continue to use the snoopy library for as long as the process runs. Don't forget that echo is a shell built-in and will not be logged (and command echo does not work for some reason; although, this technique works for other shell build-in commands.

Jordan Sissel offers liboverride, which is a small toolset that lets you quickly inject code into another program.

Example

An example of hooking into a library call using LD_PRELOAD:

/* This example shows how to hook into library calls using LD_PRELOAD.
 * This example hooks into the malloc() call. This is not a "serious"
 * example. See the end of this comment to see why.
 *
 * To build this example run the following:
 *      gcc -ldl -Wall -shared -fPIC -o malloc_hook.so -D_GNU_SOURCE malloc_hook.c
 * To test this example run the following:
 *      LD_PRELOAD=./malloc_hook.so ls -l /proc
 * Note that we need -D_GNU_SOURCE to make this work. This enables
 * some non-standard GNU extensions. Without this we would get
 * this compilation error:
 *     malloc_hook.c:51: error: 'RTLD_NEXT' undeclared (first use in this function)
 *
 * Note that when you hook into a library call you usually want to
 * eventually hand off the work to the original call.
 * Beware because you can't simply call the original library call
 * because your hook is running under the LD_PRELOAD modification.
 * This is what <dlfcn.h> is for. It provides the dlsym() call which
 * is used to find the address of the function. Then we call the
 * function directly by its address. The RTLD_NEXT handle used in 
 * dlsym() is specifically to allow you to create wrappers around
 * functions in another shared library.
 *
 * The next thing to notice is that hooking into malloc this way
 * is a very BAD IDEA! Notice the calls to printf() and dlsym().
 * What would have happened if these calls had tried to call
 * malloc() themselves? You would have ended up with an
 * infinite loop. We just got lucky here. It turns out that
 * Linux provides hooks for you to get around problems like this.
 * In this case we should have looked at using __malloc_hook().
 *
 * Copyright (c) 2010, Noah Spurrier <noah@noah.org>
 */

#include <dlfcn.h>
#include <stdio.h>

void *malloc(size_t size)
{
    static void * (*malloc_original)(size_t) = NULL;
    void * memory_pointer;

    /* This result of dlsym is preserved to speed up access next time.
     * This isn't a thread-safe practice, but it shouldn't matter here
     * since a library can have only one pointer to a function.
     * If it became a problem I would have removed the 'if' statement
     * and the 'static' declaration. It isn't much slower by calling
     * dlsym() every time.
     */
    if (malloc_original == NULL)
        malloc_original = (void *(*)()) dlsym(RTLD_NEXT, "malloc");

    memory_pointer = malloc_original(size);
    printf("malloc(%d) returns pointer %p\n", size, memory_pointer);     
    return memory_pointer;
}