Toon posts:

syscall hooks in Linux 2.6 kernel modules

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben even wat bezig met Linux kernel modules programming. In Linux 2.0, 2.2 en 2.4 maakte ik graag gebruik van syscall hooks, maar dat werkt in 2.6 niet meer.

Uit het archief graven wij op:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#define PATCHUID        51
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
#include <asm/segment.h>
#include <asm/unistd.h>
#include <linux/dirent.h>
#include <sys/syscall.h>
#include <sys/sysmacros.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>

MODULE_AUTHOR("uid0");
MODULE_LICENSE("GPL");

extern void* sys_call_table[];

time_t (*orig_time) (time_t *t);
time_t new_time (time_t *t);

time_t new_time(time_t *t)
time_t new_time(time_t *t)
{
        if (current->uid==PATCHUID) {
                return (time_t *)0;
        }
        return orig_time(t);
}

int init_module(void) {
        printk("Applying time() patch for uid %d\n",PATCHUID);
        orig_time=sys_call_table[SYS_time];
        sys_call_table[SYS_time]=new_time;
        return 0;
}

void cleanup_module(void) {
        sys_call_table[SYS_time]=orig_time;
        printk("Removed time() patch from uid %d\n",PATCHUID);
}

Ieder programma wat vervolgens uid 51 heeft, krijgt een foutieve tijd voorgeschoteld, namelijk 0 = 1 jan 1970 0:00. (Dit is overigens niet de actual patch die ik wil uitvoeren, maar het is zo een simpel voorbeeldje.)

De zelfde code voor de Linux 2.6 kernel zou zijn:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#define PATCHUID        51
#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/version.h>
#include <linux/dirent.h>
#include <linux/sched.h>
#include <sys/syscall.h>
#include <asm/segment.h>
#include <asm/unistd.h>
#include <sys/sysmacros.h>

MODULE_AUTHOR("uid0");
MODULE_LICENSE("GPL");

extern void* sys_call_table[];

static time_t (*orig_time) (time_t *t);
time_t new_time (time_t *t);

time_t new_time(time_t *t)
{
        if (current->uid==PATCHUID) {
                return (time_t *)0;
        }
        return orig_time(t);
}

static int __init xinit_module(void) {
        printk("Applying time() patch for uid %d\n",PATCHUID);
        orig_time=sys_call_table[SYS_time];
        sys_call_table[SYS_time]=new_time;
        return 0;
}

static void __exit xcleanup_module(void) {
        sys_call_table[SYS_time]=orig_time;
        printk("Removed time() patch from uid %d\n",PATCHUID);
}

module_init(xinit_module);
module_exit(xcleanup_module);

ware het niet dat Linux 2.6 de sys_call_table niet exporteert. Make (andere makefile) gaat prima, maar modprobe niet, omdat er unknown symbols zijn. Spreekt voor zich.

Ik heb nu de volgende oplossingen gevonden:
  • patch de kernel, zodat deze weer wel sys_call_table exporteert. Heel simpel, maar breekt de compatibiliteit met ongepatchte distro's. Daarnaast is het niet voor niets verwijderd uit 2.6, deze methode van hooken kan namelijk race condities en andere smp problemen opleveren.
  • kernel hacking, zie http://www.phrack.org/phrack/58/p58-0x08 . Leuk, maar eigenlijk heel ranzig.
Zijn er misschien (ondertussen) ook andere methodes? Een functie om symbols te hooken zou geen kwaad kunnen.

  • Martin Sturm
  • Registratie: December 1999
  • Laatst online: 09-01 07:28
Het is niet zo makkelijk (meer) om syscall functies te overriden. Dat is uit veiligheidsoverwegingen, en omdat er weinig praktisch nut voor is. Bepaalde syscalls worden afaik nog wel geëxporteerd, maar de meeste niet. Voor zover ik weet zijn alleen de twee oplossingen die je zelf noemt een mogelijkheid.
(vorig jaar voor een vak precies dezelfde opdracht gehad (om dus de time syscall te overriden .. ))

  • serkoon
  • Registratie: April 2000
  • Niet online

serkoon

mekker.

Gewoon een jump over de eerste paar bytes van de originele syscall heen gooien. Dat is niet of nauwelijks racebaar en eigenlijk wel de de facto manier waarop men (lees: evile kernelmodulebouwers) het doet :)

Je kunt vast ook de syscall table opzoeken met wat ELF-foo of simpelweg door kernel space door te stampen op zoek naar een bekende structuur of wat bekende adressen. Die laatste lijkt mij de lelijkste manier.

Geeft al weer aan dat het niet exporteren onder het mom van veiligheid geen enkel nut heeft. Een kernelmodule als adore of suckit zal dan gewoon op een enge manier syscalls afvangen, maar de hacker met zuivere motieven moet dat dus ook en krijgt daardoor crappy code..

  • irondog
  • Registratie: Januari 2001
  • Laatst online: 11-05-2025

irondog

alle dingen moeten onzin zijn

Let op dat Glibc functies gemakkelijk te 'overloaden' zijn. Misschien is het handiger een Libc hack toe te passen dan een kernel hack. Kijk ff naar het LD_PRELOAD voorbeeld hieronder. Hiermee heb ik de time() functie in libc vervangen door mijn eigen.

time.c
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <time.h>
#include <dlfcn.h>

time_t time(time_t *t) {
        /* declareer een pointer naar een functie */
        time_t* (*func)(time_t*);

        /* laat de pointer wijzen naar de onderliggende tijdfunctie */
        func = (time_t*)dlsym((void*) -1L, "time");

        /* doe wat leuks */
        printf("hallo, het is tijd om te hacken\n");

        /* toch maar de eche libc functie uitvoeren */
        return (*func)(t);
}

Compilen met:
gcc -shared time.c -otime.so -ldl

testtime.c
code:
1
2
3
4
#include <time.h>
main() {
        printf("het is nu in unix time: %u\n", time(0));
}

Compilen met:
gcc testtime.c -otest

Testen:
LD_PRELOAD="./time.so" ./test

[P5B deluxe] [Core2Duo 6300] [2 X 1GB DDR2] [GF FX7300] [320 GB WD] [Gentoo] [VISTA]


Verwijderd

Topicstarter
Als eerste: allen bedankt voor de input.
Martin Sturm schreef op maandag 13 juni 2005 @ 16:51:
Het is niet zo makkelijk (meer) om syscall functies te overriden. Dat is uit veiligheidsoverwegingen, en omdat er weinig praktisch nut voor is. Bepaalde syscalls worden afaik nog wel geëxporteerd, maar de meeste niet. Voor zover ik weet zijn alleen de twee oplossingen die je zelf noemt een mogelijkheid.
(vorig jaar voor een vak precies dezelfde opdracht gehad (om dus de time syscall te overriden .. ))
De syscalls worden wel geexporteerd... maar de symbol table naar die syscalls dus niet. En die heb je best wel nodig om op nette wijze te hooken.
serkoon schreef op maandag 13 juni 2005 @ 20:00:
Gewoon een jump over de eerste paar bytes van de originele syscall heen gooien. Dat is niet of nauwelijks racebaar en eigenlijk wel de de facto manier waarop men (lees: evile kernelmodulebouwers) het doet :)
...
Geeft al weer aan dat het niet exporteren onder het mom van veiligheid geen enkel nut heeft. Een kernelmodule als adore of suckit zal dan gewoon op een enge manier syscalls afvangen, maar de hacker met zuivere motieven moet dat dus ook en krijgt daardoor crappy code..
De belangrijkste reden die Linus geeft, is niet om rootkits tegen te houden, maar race condities voorkomen. Maar voor evil mannetjes is het inderdaad een eitje om een LKM te bouwen. En compleet te hiden ook.
irondog schreef op maandag 13 juni 2005 @ 21:08:
Let op dat Glibc functies gemakkelijk te 'overloaden' zijn. Misschien is het handiger een Libc hack toe te passen dan een kernel hack. Kijk ff naar het LD_PRELOAD voorbeeld hieronder. Hiermee heb ik de time() functie in libc vervangen door mijn eigen.
Thanks voor de suggestie. Maar voor de toepassing waar ik het voor nodig heb, is het voor veiligheidsredenen niet toegestaan dat een gebruiker de hooks kan uitschakelen. Ik had er al aan gedacht, maar het is gewoon niet veilig.
Het ging overigens niet om de time() functie, maar die gebruikte ik even omdat dat een makkelijk voorbeeld geeft.

Ik denk dat ik er morgen maar een complete kernel patch van ga maken. Of ik nu de symbol table export ga patchen, of de betreffende functies maakt ook niet uit.