Artificial truth

The more you see, the less you believe.

[archives] [latest] | [homepage] | [atom/rss]

Fun with LD_PRELOAD
Thu 23 August 2012 — download

On Linux, you can do pretty neat tricks with dynamic libraries.

Theory

The manpage of ld.so tells us :

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. For setuid/setgid ELF bina‐ ries, only libraries in the standard search directories that are also setgid will be loaded.

Nice, we are able to put some libraries before others, without recompiling. Soooooooo, we can force a program to use our functions instead of the dynamically loaded ones.

Example

Given a code like this:

#include <stdio.h>
#include <string.h>

char* KEY = "secret";

int main(int argc, char* argv[]){
    if(argc <2){
        printf("Usage: %s <secret_password>n", argv[0]);
        return 1;
    }

    if(! strcmp(KEY, argv[1]))
        printf("Goodboyn");
    else
        printf("Badboyn");

    return 0;
}

It would be nice if we could replace the strcmp function with something more verbose, like this:

int strcmp(const char* s1, const char* s2){
    printf("s1: %sn", s1);
    printf("s2: %sn", s2);
    return 0;
}

Our function always returns 0 (Which means "strings are equals" in regular strcmp) and shows us the two strings.

$ gcc -fPIC -c strcmp.c -o strcmp.o
$ gcc -shared -o strcmp.so strcmp.o

This will compile our crafted strcmp function as a shared lib.

$ LD_PRELOAD="./live_patch.so" a.out azerty
s1: secret
s2: azerty
Goodboy

Woot !

Even more fun

Remember the ptrace trick to detect debugging ? It can be bypassed by a custom ptrace function:

int ptrace(int request, int pid, int addr, int data){
    return 0;
}

Of course, this need to be adapted if a more elaborate trick than ptrace(PTRACE_TRACEME, ...) is used.

But this can be countered by looking at the environment variables, with, for example, the getenv function. So, we could do this to counter this counter-measure:

char *getenv(const char *name){
    return 0;
}

And so on ;)

Resources