In der Linux-Welt gibt es einige kommerzielle Software, die die MAC-Adresse des Netzwerkinterfaces als CPU-ID verwendet. Wenn man in einem Rechner, für den solche Software lizenziert ist, die Netzwerkkarte tauscht, läuft die entsprechende Software folgerichtig nicht mehr und man hat ein Problem. Nicht immer existiert die Möglichkeit, die MAC-Adresse der neuen Karte einfach auf die alte Adresse zu ändern.
Dank LD_PRELOAD gibt es jedoch eine Möglichkeit, den entsprechenden ioctl abzufangen und so die MAC-Adresse für einzelne Programme individuell zu ändern ohne irgendeine Einstellung ändern zu müssen.
Hier ist etwas Beispielcode für Linux auf der 32-Bit-Intel-Plattform:
// fsc 2005
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <dlfcn.h>
#include <time.h>
static char * libc = "/lib/libc.so.6";
static char * fake = "ADDEFECABEBA";
static void * dl;
static int (* org_ioctl)(int, unsigned long int, ...);
void _init() {
dl = dlopen(libc, RTLD_NOW);
if(!dl) {
fprintf(stderr, "oh crap: dlopen: %s\n", dlerror());
exit(1);
}
org_ioctl = dlsym(dl, "ioctl");
if(!org_ioctl) {
fprintf(stderr, "oh crap: dlsym: %s\n", dlerror());
exit(1);
}
}
int ioctl(int fd, unsigned long int request, ...) {
if(request == SIOCGIFHWADDR) {
va_list ap;
va_start(ap, request);
struct ifreq *u = va_arg(ap, struct ifreq *);
unsigned char *t = u->ifr_hwaddr.sa_data;
sscanf(fake, "%04hx%04hx%04hx", t, t+2, t+4);
u->ifr_hwaddr.sa_family = 1;
va_end(ap);
} else {
asm("movl %ebp, %esp");
asm("popl %ebp");
asm("jmpl *org_ioctl");
}
return 0;
}
Das ganze wirkt dann so:
fsc@chloris ld_preload> gcc -O0 -nostdlib -shared -ldl -o libfakemac.so fakemac.c
fsc@chloris ld_preload> LD_PRELOAD=./libfakemac.so ifconfig | grep HWaddr
eth0 Link encap:Ethernet HWaddr DE:AD:CA:FE:BA:BE
lo Link encap:Ethernet HWaddr DE:AD:CA:FE:BA:BE
Für AMD64 habe ich das auch noch:
// fsc 2005
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <dlfcn.h>
#include <time.h>
static char * libc = "/lib/libc.so.6";
static char * fake = "ADDEFECABEBA";
static void * dl;
static int (* org_ioctl)(int, unsigned long int, ...);
void _init() {
dl = dlopen(libc, RTLD_NOW);
if(!dl) {
fprintf(stderr, "oh crap: dlopen: %s\n", dlerror());
exit(1);
}
org_ioctl = dlsym(dl, "ioctl");
if(!org_ioctl) {
fprintf(stderr, "oh crap: dlsym: %s\n", dlerror());
exit(1);
}
}
asm(".globl ioctl");
asm(".type ioctl, @function");
asm("ioctl: cmpq $35111, %rsi");
asm(" jne .ioc1");
asm(" jmp my_ioctl");
asm(".ioc1: movq org_ioctl(%rip), %rax");
asm(" jmp *%rax");
asm(".size ioctl, .-ioctl");
int my_ioctl(int fd, unsigned long int request, ...) {
if(request == SIOCGIFHWADDR) {
va_list ap;
va_start(ap, request);
struct ifreq *u = va_arg(ap, struct ifreq *);
unsigned char *t = u->ifr_hwaddr.sa_data;
sscanf(fake, "%04hx%04hx%04hx", t, t+2, t+4);
u->ifr_hwaddr.sa_family = 1;
va_end(ap);
}
return 0;
}
Wirkung auf einer Opteron-Workstation:
fsc@centauri ld_preload> gcc -O0 -nostdlib -shared -fPIC -ldl -o libfakemac64.so fakemac64.c
fsc@centauri ld_preload> LD_PRELOAD=./libfakemac64.so ifconfig | grep HWaddr
eth0 Link encap:Ethernet HWaddr DE:AD:CA:FE:BA:BE
lo Link encap:Ethernet HWaddr DE:AD:CA:FE:BA:BE