LD_PRELOAD
can do this on linux; first up our application to modify, app.c
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char c;
int fd;
fd = open(*++argv, O_RDONLY);
read(fd, &c, 1);
printf("%c\n", c);
return 0;
}
which serves to read a character from a file:
$ make app
cc app.c -o app
$ echo a > a
$ echo b > b
$ ./app a ; ./app b
a
b
changing this up requires a library that fakes out open
, fakeopen.c
:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
typedef int (*orig_open) (const char *path, int oflag, ...);
int open(const char *path, int oflag, ...)
{
orig_open fn;
mode_t cmode = 0;
va_list ap;
if ((oflag & O_CREAT) == O_CREAT) {
va_start(ap, oflag);
cmode = (mode_t) va_arg(ap, int);
va_end(ap);
}
if (strncmp(path, "a", 2) == 0)
path = getenv("FAKE");
fn = (orig_open) dlsym(RTLD_NEXT, "open");
return fn(path, oflag, cmode);
}
which when compiled and used via LD_PRELOAD
and when the filename is what we're looking for and assuming FAKE
has something that is the path:
$ cat Makefile
fakeopen.so: fakeopen.c
$(CC) $(CFLAGS) -shared -fPIC -ldl fakeopen.c -o fakeopen.so
$ rm fakeopen.so
$ cat Makefile
fakeopen.so: fakeopen.c
$(CC) $(CFLAGS) -shared -fPIC -ldl fakeopen.c -o fakeopen.so
$ make fakeopen.so
cc -shared -fPIC -ldl fakeopen.c -o fakeopen.so
$ FAKE=b LD_PRELOAD=`pwd`/fakeopen.so ./app a
b
we can make ./app a
instead read file b
. Of course there will need to be more error checking and other rakes that may be stepped on, but this should be the gist of modifying an open(2)
call.
fakeopen.so
will work willcat file
but not withsort file
. And it's the same with all libc functions that call open(2) internally. – Nov 27 '18 at 13:27