Weil jemand im IRC danach gesucht hat, hier ein kleines Stück Code um die Zeit für ein Programm zurückzusetzen. Ziemlich alle Unixoide Programme werden wohl den Systemcall gettimeofday benutzen, um die Uhrzeit zu bekommen. Zum Glück ruft man syscalls nicht von Hand auf, denn es gibt ganz viele schöne Wrapperfunktionen in der libc. In dem Fall die gut benannte Funktion gettimeofday. Nun wird die libc meistens dynamisch verlinkt, so dass man einen weit verbreiteten Trick anwenden kann, um System Calls zu hijacken. Der dynamische Loader kann nämlich Libraries “vorschalten”. Im Klartext heisst das also: wir tun gar nicht Syscalls hijacken, sondern die Wrapperfunktionen zu diesen Syscalls. Und weil wir selber so faul sind, wollen wir aus unserer Hijackfunktion nicht noch selber den richtigen Syscall aufrufen, sondern rufen gleich die eigentlich Funktion auf. Im Code sieht das dann so aus:
#include <stdlib.h>
#include <sys/time.h>
#include <dlfcn.h>
#include <assert.h>
typedef int (*gettimeofday_t)(struct timeval *, struct timezone *);
static gettimeofday_t old_gettimeofday = NULL;
#ifndef RTLD_NEXT
/* linux... */
#define RTLD_NEXT (-1l)
#endif
int gettimeofday(struct timeval *tp, struct timezone *tzp) {
int ret;
if (old_gettimeofday == NULL) {
old_gettimeofday = (gettimeofday_t)dlsym(RTLD_NEXT, "gettimeofday");
assert(old_gettimeofday != NULL);
}
ret = (*old_gettimeofday)(tp, tzp);
if (tp) {
tp->tv_sec -= 50000;
}
return ret;
}
Als erstes checken wir ob wir schon die Adresse von der “richtigen” Funktion kennen, und wenn nicht, dann holen wir die uns mit der Funktion dlsym. An der Stelle ein kleiner übler Hack für Linux. Da muss man irgendwie __USE_GNU definieren, damit der sich die gewollte Definition von dlsym holt, nach 2 Versuchen ging das bei mir irgendwie nicht, ich hatte nicht weiter bock, deswegen dieses #define RTLD_NEXT. Nachdem wir die alte Funktion haben, rufen wir diese auf, ziehen 5000 Sekunden von dem Ergebnis ab, et voila. Das Ganze kann mit folgendem Makefile compilen:
all: libfakedate.so
libfakedate.so: fakedate.c
$(CC) -D__USE_GNU -fPIC -shared -o $@ $
Und mit folgender Zeile dann benutzen:
$ LD_PRELOAD=`pwd`/libfakedate.so date
Schick! Unter OSX tut das nicht, sondern loopt, aus welchen undefinierbaren Gründen auch immer (kein ELF, sondern Mach-O, portiertes dlcompat, ach-weiss-ich…).
use: -D__GNU_SOURCE instead of -D__USE_GNU
and the switch -ldl