Kalandjaim LD_PRELOAD-dal

bAndie91 küldte be szo, 2013-04-20 07:21 időpontban

Ebben a bejegyzésemben egy apró de annál hasznosabb hack-et mutatok be.

Tudjuk, hogy a gyakran használt függvények és eljárások az operációs rendszer ''megosztott függvénykönyvtáraiban'' helyezkednek el és a dinamikusan linkelt programok innen idézik be saját kódjukba, ezzel lehetõséget adva, arra hogy a bináris állományuk kisebb legyen.
Emellett az az áldásos dolog is következik ebbõl a technikából, hogy a ''shared library''-kban tárolt jól ismert függvények kiegészítésével vagy átírásával okosíthatjuk, kifigyelhetjük, eltéríthetjük a rájuk támaszkodó programokat. Preload technika, LD_PRELOAD pedig a környezeti változó neve (lásd melléklet).
Így tettem én is az [http://en.wikipedia.org/wiki/X2vnc x2vnc] program esetében.
:Az x2vnc arra való, hogy az X11 képernyõt megtoldja egy VNC által hordozott képernyõvel és továbbítsa az egérmozgást és a gépelést billentyũzetrõl. A munkaasztal megosztására, ablakok áthúzására éppenséggel nem képes, de így is kényelmes segítség a több számítógép elõtt dolgozók számára.
Az elégedetlenségem oka az volt, hogy - bár egy switch-elt LAN-ban vagyok a vnc-t futtató géppel - elõfordul, hogy újraindítom, lefagy, kirúgom a kábelt, tehát megszakad az x2vnc hálózati kapcsolata és ilyenkor az egérmutatóm és vele együtt a gépelési fókusz ottmarad a semmiben! Az x2vnc várja, amíg a hálózati stack kézbesíti a legutóbbi egérmozgató parancsát...
Elõször gondoltam, majd a TCP socket-ot okosítom meg mondván "haver, kettõ szegmens retransmitt után hagyd a fenébe, mert az a peer halott!". Persze nem rendszerszinten alkalmaztam volna, csak az x2vnc által nyitott socket-ekre.
Ennél sokkal egyszerũbbnek bizonyult a következõ:

ssize_t write(int fd, const void *buf, size_t count)
{
int (*real_write)(int fd, const void *buf, size_t count) = NULL;
int real_write_return;
int alarm_sec = 2;
/* ... */
alarm(alarm_sec);
real_write_return = real_write(fd, buf, count);
alarm(0);
return real_write_return;
}

A program végsõ soron a write(2) hívást használja, hogy a hálózatra adatot küldjön. Meghatároztam egy kettõ másodperces türelmi idõt (alarm_sec változó), ameddig a rendszerhívásban tartózkodhat. Az alarm() függvénnyel húzom fel az ''ébresztõórát'' és amikor csörög, a folyamatszál kap egy SIGALRM-ot én pedig visszakapom az irányítást (és lecsapom a wekkert: alram(0)).

A teljes kódért nyisd meg a csatolt fájlt.

bAndie91 küldte be szo, 2013-04-20 07:33 időpontban

Permalink

#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count)
{
int (*real_write)(int fd, const void *buf, size_t count) = NULL;
int real_write_return;
int alarm_sec = 2;

if (real_write == NULL) {
void *handle = dlopen("/lib/libc.so.6", RTLD_LAZY);
if (handle == NULL) {
fprintf(stderr, "dlopen: %s\n", dlerror());
exit(1);
}
real_write = dlsym(handle, "write");
if (real_write == NULL) {
fprintf(stderr, "dlsym: %s\n", dlerror());
exit(1);
}
}

alarm(alarm_sec);
real_write_return = real_write(fd, buf, count);
alarm(0);
return real_write_return;
}

// Fordítás: gcc -s -x c alarmwrite.c -fPIC -shared -o alarmwrite.so
// Futtatás: LD_PRELOAD=./alarmwrite.so x2vnc host:display

bAndie91 küldte be h, 2016-12-19 14:36 időpontban

Permalink

Egyszerűbb lett volna elolvasni a manuált és felfedezni hogy vagy -hotkey kapcsoló, amivel - igaz plusz interakcióval, de - elérhető ez a viselkedés.
[Ctrl][F12]-t kell nyomni hogy visszavegye a kontrollt :-)