LD PRELOAD notes

From Noah.org
Revision as of 22:53, 20 May 2010 by Root (talk | contribs)
Jump to navigationJump to search

Contents

See also ptrace notes for debugging down to the CPU instruction level.

Jordan Sissel offers liboverride, which is a small toolset which 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().
 *
 * Noah Spurrier 2010
 */

#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;
}