Trapping System Calls

Do you remember MS-DOS? In that operating system, stealth technology was implemented by replacing the int 13h/int 21h interrupts. In Linux, the same goal is achieved by trapping system calls (or syscalls for short). To conceal processes and files, it is enough to trap only one of them, getdents , on which the well-known readdir relies. As indicated by its name , readdir reads the contents of directories (including the /proc directory). Note that in general, there is no other way of viewing the list of processes under Linux. The trapping function intercepts get-dents and views the result that it returns, cutting out everything "unneeded" from it. In other words, the trapping function works as a filter.

Network connections are concealed in a similar way (they are mounted to /proc/net ). To disguise a network sniffer, it is necessary to trap the ioctl system call, suppressing the PROMISC flag. Trapping the get_kernel_symbols system call allows you to conceal the LKM in such a way that no one would be able to find it.

This looks promising . Now it only remains to implement this technique. The kernel exports the extern void sys_call_table variable, which contains an array of pointers to syscalls. Every cell of this array contains a valid pointer to the appropriate syscall or NULL , which indicates that this syscall is not implemented in the system.

Thus, the hacker simply declares the *sys_call_table [] variable in the custom module and gains access to all syscalls. The names of known syscalls are listed in the /usr/include/sys/syscall.h file. In particular, sys_call_table[SYS_getdents] returns the pointer to getdents .

The simplest example of trapping syscalls is shown in Listing 13.7. More detailed information on this topic is provided in the " Weakening the Linux Kernel " article published in issue 52 of the Phrack e-zine.

Listing 13.7: Technique of trapping system calls
image from book
 // The pointer to the system calls table extern void *sys_call_table[]; // Pointers to old system calls int (*o_getdents) (uint, struct dirent *, uint); // Trapping! int init_module(void) {         // Obtain the pointer to the original         // SYS_getdents system call         // and save it in the o_getdents variable.         o_getdents = sys call_table[SYS_getdents];         // Insert the pointer to the trapper function         // (to save space, the code of the trapper         // is not provided).         sys_call_table[SYS_getdents] = (void *) n_getdents;         // Return         return 0; } // Restore original handlers void cleanup_module(void) {         sys_call_table[SYS_getdents] = o_getdents; } 
image from book
 

Most rootkits operate according to this principle; however, when dealing with an unknown kernel most of them crash or simply cease to operate (Fig. 13.5). It's no wonder ; the syscalls layout changes from kernel to kernel.

image from book
Figure 13.5: The consequences of a failed attempt at trapping syscalls


Shellcoder's Programming Uncovered
Shellcoders Programming Uncovered (Uncovered series)
ISBN: 193176946X
EAN: 2147483647
Year: 2003
Pages: 164

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net