[Linux x86 kernel funciton hooking emulation] [Moteur de detournement de fonctions sur Linux/INTEL] mayhem 8 décembre 2001 Translation by eberkut --[ Sommaire 1 - Introduction 1.1 - Histoire 1.2 - Nouveaux besoins 2 - Bases du Hooking 2.1 - Techniques habituelles 2.2 - Choses a ne pas oublier 3 - Le code explique (en ASM) 4 - Utiliser la bibliotheque (en C) 4.1 - l'API 4.2 - Resolution de symbole kernel 4.3 - l'objet hook_t 5 - Tester le code 5.1 - Charger le module 5.2 - Jouer un peu 5.3 - Le code 6 - References --[ 1 - Introduction Abuser, loguer, patcher, ou meme debuguer : autant de raisons evidentes de penser que le hooking est important. Nous essyaerons de comprendre comme cela fonctionne. Le contexte de la demonstration est l'environnement du kernel Linux. L'article se termine par une bibliotheque generaliste de hooking pour la serie des kernels linux 2.4.x, developpe sur 2.4.5 et fonctionnant sur IA32, elle s'appelle LKH, Linux Kernel Hooker. ----[ 1.1 - Histoire Une des references sur le sujet de l'hijacking de fonction a ete publie publie en Novembre 1999 par Silvio Cesare. Cette implementation tres avant-gardiste permettait de filtrer l'acces a la fonction du kernel acct_process() utilisee pour accounter le process (voir process accouting) . La technique etait de modifier les premiers octets de la fonction pour sauter vers un autre code et decider si la fonction originale doit etre appele ou non . ----[ 1.2 - Nouveaux besoins Quelques avancees ont ete realise depuis ce temps : - L'utilisation pragmatique de la redirection necessite generalement (toujours ?) l'acces aux parametres originaux, quelque soit leur nombre et leur taille (par exemple si nous voulons modifier et faire suivre des paquets IP). - Nous pouvons avoir besoin de desactiver le hook a la demande, ce qui est parfait pour la configuration du kernel en cours d'execution. Nous pouvons vouloir appeler les fonctions originales (hooking discret, utilise par les programmes de monitoring) ou non (hooking agressif, utilise , par exemple, par les patchs de securite pour gerer les ACL, Access Control Lists, ou bien beaucoup d'autres choses que je vous laisse decouvrir ;) sur les structures du kernel . - Dans certains cas, nous pouvons aussi vouloir detruire le hook juste apres le premier appel, par exemple pour effectuer des appels par frequence (nous pouvons hooker une fois chaque seconde ou chaque minute). --[ 2 - Bases du Hooking ----[ 2.1 Techniques habituelles Bien sur, le coeur du code de hooking doit etre fait en language assembleur, mais le code wrapper de hooking est fait en C. L'interface haut niveau de LKH est decrite dans la section API. Comprenons bien quelques bases du detournement . Voici ce qu'est basiquement le hooking : - Modifier le debut du code d'une fonction pour pointer sur un autre code (appele 'code de hooking'). Ceci est une tres ancienne et efficace maniere de faire ce que nous voulons. Une autre maniere de faire ceci est de patcher toutes les references a la fonction dans toutes les pages de code referencant cette fonction. Cette seconde methode a quelques avantages (c'est tres discret) mais l'implementation est assez complexe (necessite le parsing des pde/pte) et un peu lente . - Modifier pendant l'execution l'adresse de retour de la fonction pour prendre le controle quand l'execution de la fonction hookee est fini. - Le code de hook doit avoir 2 parties differentes, la premiere doit etre execuritee avant la fonction (preparer la pile pour acceder aux parametres, lancer des callbacks, restorer l'ancien code de la fonction), la seconde doit etre execute apres (réinstaller le hook apres si besoin est). - Les parametres par defaut (definissant le comportement du hook) doivent etre selectionnes durant la creation du hook (avant de modifier le code de la fonction). - Ajouter des callbacks. Chaque callback peut acceder et meme modifier les parametres de la fonction originale. - Activer, desactiver, changer les parametres, ajouter ou supprimer de= callbacks quand nous voulons. ----[ 2.2 - Choses a ne pas oublier -> Fonctions sans frame pointer : Une importante fonctionnalite est la capacite de hooker des fonctions compilees avec l'option gcc -fomit-frame-pointer. Cette fonctionnalite requiert de la part du code de hooking d'etre independant de %ebp, c'est pourquoi nous utiliserons uniquement %esp pour les operations sur la pile. Nous avons aussi a mettre a jour certaines parties (quelques octets ici et la) pour fixer les offsets relatifs a %esp dans le code de hook. Regardez khook_create dans lkh.c pour plus de details a ce sujet. Le code de hook doit aussi etre independant de la position. C'est pourquoi autant d'offsets dans le code de hook sont corriges en cours d'execution (puisque nous sommes dans le kernel, les offsets doivent etre corriges durant la creation du hook, mais notons des techniques tres similaires peuvent etre utilisees pour le hooking de fonction sur des processus *en cours d'execution*). -> Recursion=20 Nous devons etre capable d'appeler la fonction originale depuis un callback, donc le code original doit etre restaure avant l'execution de n'importe quel callback. -> Valeurs de retour Nous devons retourner la valeur correcte dans %eax, que nous ayons des callbacks ou non, que la fonction originale soit appelee ou non. Dans la demonstration, la valeur de retour du dernier callback execute est retournee si la fonction originale n'est pas appele. Si aucun callback ni fonction d'origine n'est appele, la valeur de retour est hors de notre controle. -> POST callbacks Vous ne pouvez pas acceder aux parametres de fonction si vous executez des callbacks apres la fonction d'origine. C'est pourquoi c'est une mauvaise idee. Cependant, voici la technique pour le faire : - parametrer le hook comme agressif - appeler les callback desires avant la fonction . - appeler la fonction d'origine depuis un callback avec ses propres parametres - appelez le callback desires apres la fonction . --[ 3 - Le code explique D'abord nous installons le hook. A - Nous reecrivons les 7 premiers octets de la routine detournee avec un saut indirect (indirect jmp) pointant vers la zone du code de hook. L'offset place dans %eax est l'adresse absolue du code de hook, donc chaque fois que nous appellerons la fonction hijack_me(), le code de hook prendra le controle. Avant hijack : 0x80485ec : mov 0x4(%esp,1),%eax 0x80485f0 : push %eax 0x80485f1 : push $0x8048e00 0x80485f6 : call 0x80484f0 0x80485fb : add $0x8,%esp Apres hijack : 0x80485ec : mov $0x804a323,%eax 0x80485f1 : jmp *%eax 0x80485f3 : movl (%eax,%ecx,1),%es 0x80485f6 : call 0x80484f0 0x80485fb : add $0x8,%esp Les 3 instructions affichees apres le jmp ne signifie rien puisque gdb est trompe par notre hook et interprete mal les opcodes des instructions tronquees . B - Replacer les octets orignaux de la fonction hookee, nous avons besoin de ca si nous voulons appeler la fonction d'origine depuis un callback sans casser quoi que ce soit. pusha movl $0x00, %esi (1) movl $0x00, %edi (2) push %ds pop %es cld xor %ecx, %ecx movb $0x07, %cl rep movsl Les 2 offsets NULL ont en fait ete modifie durant la creation du hook (puisque leurs valeurs dependent de l'offset de la fonction hookee, nous devons patcher le code de hook en cours d'execution). (1) est fixee avec l'offset du buffer contenant les premiers 7 octets de la fonction d'origine. (2) est fixee avec l'adresse de la fonction originale. Si vous etes familier avec le langage assembleur x86, vous devez savoir que ces instructions vont copier %ecx octets depuis %ds:%esi vers %es:%edi. Referez vous a [2] pour les specifications des instructions INTEL. C - Initialiser la pile pour permettre l'acces aux parametres en lecture et en ecriture et lancer nos callbacks. Nous deplacons l'adresse du premier parametre original dans %eax puis nous le mettons sur la pile (push) . leal 8(%esp), %eax push %eax nop; nop; nop; nop; nop nop; nop; nop; nop; nop nop; nop; nop; nop; nop nop; nop; nop; nop; nop nop; nop; nop; nop; nop nop; nop; nop; nop; nop nop; nop; nop; nop; nop nop; nop; nop; nop; nop Notez que les slots vides sont pleins d'instructions NOP (opcode 0x90) . Cela signifie no operation. Quand un slot est rempli (en utilisant la fonction khook_add_entry), 5 octets sont utilises : - l'opcode de l'appel (opcode 0xE8) - l'offset du callback (adresse relative de 4 octets) Nous choisissons de selectionner un maximum de 8 callbacks. Chacun des callbacks inseres sont appeles avec un parametre (la valeur push'ed de %eax contient l'adresse des parametres de la fonction d'origine, parametres reposant sur la pile) . D - Restaurer la pile add $0x04, %esp Nous retirons maintenant l'adresse des parametres de la fonction d'origine push'ed en (C). De cette facon, %esp est remis a son ancienne valeur (celle avant d'effectuer l'etape C). A ce moment, la pile ne contient pas la stack frame de la fonction d'origine puisqu'elle a ete reecrite a l'etape (A). E - Modifier l'adresse de retour de la fonction originale . Sur les processeurs Intel, les adresses de retour de fonctions sont sauvees sur la pile, ce qui n'est pas un tres bonne idee pour des raisons de securite ;-). Cette modification nous permet de retourner ou nous voulons (au hook-code) apres l'execution de la fonction d'origine. Puis nous appelons la fonction originale. Au retour, le code de hook regagne le controle. Jetons a oeil a ceci attentivement : -> D'abord nous prenons notre %eip actuel et le sauvons dans %esi (les labels de fin pointent sur du code que vous pouvez facilement identifier a l'etape E5). Cette astuce est toujours utilisee dans les codes independant de la position) 1. jmp end begin: pop %esi -> Ensuite nous rapportons l'ancienne adresse de retour reposant a 4(%esp) et la sauvegardons dans %eax. 2. movl 4(%esp), %eax -> Nous utilisons cette adresse de retour sauvee comme un offset de= 4 octets a la fin du code de hook (voir le pointeur NULL a l'etape H), que nous pourrons utiliser retourner a la la fin du processus de hooking pour retourner a la bonne place . 3. movl %eax, 20(%esi) -> Nous modifions l'adresse de retour de la fonction d'origine ainsi nous pourrions retourner juster apres l'instruction 'call begin' . 4. movl %esi, 4(%esp) movl $0x00, %eax -> Nous appelons la fonction d'origine. Le label 'end' est utilise dans l'etape 1, et le label 'begin' pointe sur le code juste apres le 'jmp end' (toujours dans l'etape 1). La fonction d'origine retournera juste apres l'instruction 'call begin' puisque nous avons change son adresse de retour. 5. jmp *%eax end: call begin F - Retour au code de hooking. Nous selectionnons encore les 7 diaboliques octets dans le code de la fonction originale. Ces octets ont ete remis a leurs valeurs originales avant d'appeler la fonction, donc nous avons besoin de hooker la fonction encore une fois (comme dans l'etape A). Cette etape est nop'ed (replace par des instructions NOP) si le hook est single-shot (non permanent), donc les 7 octets de notre diabolique saut indirect (etape A) ne sont pas copie encore une fois. Cette etape est tres proche de l'etape (B) puisque il utilise le meme mecanisme de copie (utilisant des instructions rep movs*), donc referez vous a ces etapes pour des explications. Les offsets NULL dans le code doivent etre fixes pendant la creation du hook : - le premier (le buffer source) est remplace par l'addresse du buffer des octets diaboliques (voir structure hook_t) - le second (le buffer de destination) est remplace par l'adresse du point d'entree de la fonction d'origine. movl $0x00, %esi movl $0x00, %edi push %ds pop %es cld xor %ecx, %ecx movb $0x07, %cl rep movsb G - Utiliser l'adresse de retour originale (sauvegardee a l'etape 2) et retournons a la fonction appelante originale. L'offset NULL que vous pouvez voir (*) doit etre fixe a l'etape E2 avec l'adresse de retour de la fonction originale. La valeur d'%ecx et alors pushee sur la pile ainsi la prochaine instruction ret l'utilisera comme si c'etait un registre %eip sauvegarde sur la pile. Ceci retourne a la place originale (correcte). movl $0x00, %ecx * pushl %ecx ret --[ 4 - Utiliser la bibliotheque ----[ 4.1 - l'API L'API LKH est plutot simple a utiliser : hook_t *khook_create(int addr, int mask); Creer un hook a l'adresse 'addr'. Donne egalement le type par defaut (HOOK_PERMANENT ou HOOK_SINGLESHOT), l'etat par defaut (HOOK_ENABLED ou HOOK_DISABLED) et le mode par defaut (HOOK_AGGRESSIVE ou HOOK_DISCRETE). Le type, l'etat et le mode sont cumulables dans le parametre 'mask' . int khook_add_entry(hook_t *h, char *routine, int range); Ajoute un callback au hook au rang 'range'. Retourne -1 si le rang donne est invalide. Autrement, retourne 0. int khook_remove_entry(hook_t *h, int range); Supprime le callback place dans le slot 'range', retourne -1 si le rang donne est invalide, Autrement retourne 0. void khook_purge(hook_t *h); Supprime tous les callbacks de ce hook. int khook_set_type(hook_t *h, char type); Change le type du hook en 'h'. Le type peut etre HOOK_PERMANENT (le hookcode est execute chaque fois que la fonction hookee est appelee) ou HOOK_SINGLESHOT (le hookcade est execute seulement pour 1 hijack, puis il est proprement supprime). int khook_set_state(hook_t *h, char state); Change l'etat du hook en 'h'. L'etat peut etre HOOK_ENABLED (le hook est active) ou HOOK_DISABLED (le hook est desactive). int khook_set_mode(hook_t *h, char mode); Change le mode du hook en 'h'. Le mode peut etre HOOK_AGGRESSIVE (le hook n'appelle pas la fonction hijackee) ou HOOK_DISCRETE (le hook appelle la fonction hijackee apres avoir execute les routines de callback). Certaines parties du code de hook sont nop'ed (overwrittees avec des instruction no operation) si le hook est agressif (etapes E et H). int khook_set_attr(hook_t *h, int mask); Change le mode, etat et/ou type en utilisant un unique appel de fonction. La fonction retourne 0 en cas de succes ou -1 si le 'mask' specifie contient des options incompatibles. void khook_destroy(hook_t *h); Desactive, detruit, et libere les ressources du hook. Notez que vous pouvez ajouter ou supprimer des entrees quand vous voulez, quelque soit l'etat, le type et la monde du hook utilise. ----[ 4.2 - Resolution de symbole kernel Une fonction de resolution de symbole a ete ajoute a LKH, vous permettant d'acceder aux valeurs des fonctions exportees. int ksym_lookup(char *name); Notez que ceci retourne NULL si la symbole demeure non resolu. Cette consultation peut resoudre des symboles contenus dans la section __ksymtab du kernel, une liste exhaustive de ces symboles est affichee lors de l'execution de 'ksyms -a' bash-2.03# ksyms -a | wc -l 1136 bash-2.03# wc -l /boot/System.map 14647 /boot/System.map bash-2.03# elfsh -f /usr/src/linux/vmlinux -s # displaying sections [SECTION HEADER TABLE] (nil) --- foffset: (nil) 0 bytes [*Unknown*] (...) 0xc024d9e0 a-- __ex_table foffset: 0x14e9e0 5520 bytes [Program data] 0xc024ef70 a-- __ksymtab foffset: 0x14ff70 9008 bytes [Program data] 0xc02512a0 aw- .data foffset: 0x1522a0 99616 bytes [Program data] (...) (nil) --- .shstrtab foffset: 0x1ad260 216 bytes [String table] (nil) --- .symtab foffset: 0x1ad680 245440 bytes [Symbol table] (nil) --- .strtab foffset: 0x1e9540 263805 bytes [String table] [END] A vrai dire, la section de memoire mappee __ksymtab ne contient pas tous les symboles que nous voudrions hijacker. D'un autre cote, la section non mappee .symtab est definitivement plus grande (245440 octets contre 9008 octets). Quand nous utilisons 'ksyms', le syscall __NR_query_module (ou __NR_get_kernel_syms pour les anciens kernels) est lancee , ce syscall peut seulement acceder a la section __ksymtab puisque la table complete des symboles kernel contenue dans __ksymtab n'est pas chargee en memoire (les droits sont --- au lieu de a--) . La solution pour acceder a l'entiere table des symboles est de reprendre les offsets dans notre fichier System.map (creez le en utilisant `nm -a vmlinux > System.map`). bash-2.03# ksyms -a | grep sys_fork bash-2.03# grep sys_fork /boot/System.map c0105898 T sys_fork bash-2.03# Dans le code : #define SYS_FORK 0xc0105898 if ((s = khook_create((int) SYS_FORK, HOOK_PERMANENT, HOOK_ENABLED)) == NULL) KFATAL("init_module: Cant set hook on function *sys_fork* ! \n", -1); khook_add_entry(s, (int) fork_callback, 0); #undef SYS_FORK Pour les systeme n'ayant pas de System.map ou une image kernel non compressee (vmlinux), il est acceptable de decompresser le fichier vmlinux (faites attention, ce n'est pas un format gzip standard ! [3] contient des informations tres utiles a ce propos) et de creer manuellement un nouveau fichier System.map. Une autre facon de faire concernant la resolution de symboles kernel non exportes peut etre une consultation statistique : Analyser les references dans le code hexadecimal du kernel peut nous permettre de predire les valeurs des symboles (en regardant les offsets pour les call ou les jmp dans le code ASM), la difficulte de cet outil serait la portabilite, puisque le code kernel change d'une version a une autre. N'oubliez pas de changer SYS_FORK pour votre propre valeur d'offset sys_fork. ----[ 4.3 - LKH internes : l'objet hook_t Jetons un oeil a la structure hook_t (entite hook en memoire) : typedef struct s_hook { int addr; int offset; char saved_bytes[7]; char voodoo_bytes[7]; char hook[HOOK_SIZE]; char cache1[CACHE1_SIZE]; char cache2[CACHE2_SIZE]; } hook_t; h->addr L'adresse de la fonction d'origine, utilisee pour activer ou desactiver le hook. h->offset Ce champ contient l'offset depuis h->addr ou commencer l'overwrite pour placer le hookcode. Sa valeur est 3 ou 0, cela depend si la fonction a une stackframe ou pas. h->original_bytes Les 7 octets reecrits de la fonction originale. h->voodoo_bytes Les 7 octets que nous avons besoin de placer au debut de la fonction pour la rediriger (contient le code de saut indirect vu a l'etape A du paragraphe 3). h->hook Le buffer d'opcode contenant le code de hooking, ou nous inserons les references aux callbacks en utilisant khook_add_entry(). Les buffers cache1 et cache1 sont utilise pour faire une copie de sauvegarde de code de hook quand nous selectionnons le mode HOOK_AGGRESSIVE (puisque nous devons retirer l'appel de fonction d'origine, sauvegarder ce code est necessaire, pour eventuellement relancer le hook en mode discret par la suite). Chaque fois que vous creez un hook, une instance de hook_t est declaree et allouee. Vous devez creer un hook par fonction que vous voulez hijacker. ----[ 5 - Tester le code Verifiez d'abord http://www.devhell.org/~mayhem/ pour le code le plus recent de la librarie. Faites juste #include "lkh.c" et jouez ! Dans ce module d'exemple utilisant LKH, nous voulons hooker : - la fonction hijack_me, ici vous pouvez verifier les bons parametres passes et leur effective modification a travers les callbacks. C'est une fonction interne au module . - la fonction schedule(), hijack SINGLESHOT. - la fonction sys_fork(), hijack PERMANENT. ------[ 5.1 - Charger le module bash-2.03# make load insmod lkh.o Testing a permanent, aggressive, enabled hook with 3 callbacks: A in hijack_one = 0 -OK- B in hijack_one = 1 -OK- A in hijack_zero = 1 -OK- B in hijack_zero = 2 -OK- A in hijack_two = 2 -OK- B in hijack_two = 3 -OK- -------------------- Testing a disabled hook: A in HIJACKME!!! = 10 -OK- B in HIJACKME!!! = 20 -OK- -------------------- Calling hijack_me after the hook destruction A in HIJACKME!!! = 1 -OK- B in HIJACKME!!! = 2 -OK- SCHEDULING! ------[ 5.2 - Jouer un peu bash-2.05# ls FORKING! Makefile doc example.c lkh.c lkh.h lkh.o user user.c user.h user.o= bash-2.05# pwd /usr/src/coding/LKH (N'affiche pas FORKING! puisque pwd est une commande shell builtin :) bash-2.05# make unload FORKING! rmmod lkh; LKH unloaded - sponsorized by the /dev/hell crew! bash-2.05# ls Makefile doc example.c lkh.c lkh.h lkh.o user user.c user.h user.o bash-2.05# Vous pouvez voir "FORKING!" chaque fois que la fonction kernel sys_fork() est appelee (le hook est permanent) et "SCHEDULING!" quand la fonction kernel schedule() est appelee pour la premiere fois (puisque le hook est SINGLESHOT, la fonction schedule() est hijackee seulement une fois, puis le hook est supprime). Voici le code commente pour cette demo : ------[ 5.3 - The code /* ** LKH demonstration code, developped and tested on Linux x86 2.4.5 ** ** The Library code is attached . ** Please check http://www.devhell.org/~mayhem/ for the library {code/updates} ** ** The tarball includes a userland code (runnable from GDB), the LKH ** kernel module and its include file, and this file (lkm-example.c) ** ** Suggestions {and,or} bug reports are welcomed ! LKH 1.2 already ** in development . ** ** Special thanks to the devhell crew and EPITECH people . */ #include "lkh.c" int hijack_me(int a, int b); /* fonction hookee */ int hijack_zero(void *ptr); /* premier callback */ int hijack_one(void *ptr); /* second callback */ int hijack_two(void *ptr); /* troisieme callback */ void hijack_fork(void *ptr); /* callback sys_fork */ void hijack_schedule(void *ptr); /* callback schedule */ static hook_t *h = NULL; static hook_t *i = NULL; static hook_t *j = NULL; int init_module() { int ret; printk(KERN_ALERT "Change the SYS_FORK value then remove the return \n");= return (-1); /* ** Creer le hook */ #define SYS_FORK 0xc010584c j = khook_create(SYS_FORK , HOOK_PERMANENT | HOOK_ENABLED | HOOK_DISCRETE); #undef SYS_FORK h = khook_create(ksym_lookup("hijack_me") , HOOK_PERMANENT | HOOK_ENABLED | HOOK_AGGRESSIVE); i = khook_create(ksym_lookup("schedule") , HOOK_SINGLESHOT | HOOK_ENABLED | HOOK_DISCRETE); /* ** Encore une autre verification */ if (!h || !i || !j) { printk(KERN_ALERT "Cannot hook kernel functions \n"); return (-1); } /* ** Ajouter quelques callbacks pour les fonctions sys_fork et schedule */ khook_add_entry(i, (int) hijack_schedule, 0); khook_add_entry(j, (int) hijack_fork, 0); /* ** Tester le hook hijack_me() */ printk(KERN_ALERT "LKH: perm, aggressive, enabled hook, 3 callbacks:\n"); khook_add_entry(h, (int) hijack_zero, 1); khook_add_entry(h, (int) hijack_one, 0); khook_add_entry(h, (int) hijack_two, 2); ret = hijack_me(0, 1); printk(KERN_ALERT "--------------------\n"); printk(KERN_ALERT "Testing a disabled hook :\n"); khook_set_state(h, HOOK_DISABLED); ret = hijack_me(10, 20); khook_destroy(h); printk(KERN_ALERT "------------------\n"); printk(KERN_ALERT "Calling hijack_me after the hook destruction\n"); hijack_me(1, 2); return (0); } void cleanup_module() { khook_destroy(i); khook_destroy(j); printk(KERN_ALERT "LKH unloaded - sponsorized by the /dev/hell crew!\n"); } /* ** Fonction a hijacker */ int hijack_me(int a, int b) { printk(KERN_ALERT "A in HIJACKME!!! =3D %u \t -OK- \n", a); printk(KERN_ALERT "B in HIJACKME!!! =3D %u \t -OK- \n", b); return (42); } /* ** Premier callback pour hijack_me() */ int hijack_zero(void *ptr) { int *a; int *b; a =3D ptr; b =3D a + 1; printk(KERN_ALERT "A in hijack_zero =3D %u \t -OK- \n", *a); printk(KERN_ALERT "B in hijack_zero =3D %u \t -OK- \n", *b); (*b)++; (*a)++; return (0); } /* ** Second callback pour hijack_me() */ int hijack_one(void *ptr) { int *a; int *b; =20 a =3D ptr; b =3D a + 1; printk(KERN_ALERT "A in hijack_one =3D %u \t -OK- \n", *a); printk(KERN_ALERT "B in hijack_one =3D %u \t -OK- \n", *b); (*a)++; (*b)++; return (1); } /* ** Troisieme callback pour hijack_me() */ int hijack_two(void *ptr) { int *a; int *b; a =3D ptr; b =3D a + 1; printk(KERN_ALERT "A in hijack_two =3D %u \t -OK- \n", *a); printk(KERN_ALERT "B in hijack_two =3D %u \t -OK- \n", *b); (*a)++; (*b)++; return (2); } /* ** Callback pour schedule() (symbole kernel exporte) */ void hijack_schedule(void *ptr) { printk(KERN_ALERT "SCHEDULING! \n"); } /* ** Callback pour sys_fork() (symbole kernel non exporte) */ void hijack_fork(void *ptr) { printk(KERN_ALERT "FORKING! \n"); } --[ 6 - References [1] Kernel function hijacking http://www.big.net.au/~silvio/ [2] INTEL Developers manual http://developers.intel.com/design/pentiu m4/manuals/ [3] Linux Kernel Internals http://www.linuxdoc.org/guides.html |--[ EOF ]--------------------------------------------------------------=--|