System Call Redirection 2.6 Kernel Code That Works

Submitted by jcochett
on March 30, 2006 - 9:12pm

I have read a lot of code on system call redirection. None of it worked. I narrowed down my problem to the calling of the original function. After several weeks of misery, I found that the problems was merely a casting problems. I was very please to have some working code. It is a big relief. My project was basically at a brick wall. My teacher stated that I could take the easy way out, I am glad I stuck to it. I can't take full credit for the code, the casting solution I found with in some code called sandbox.c. I will research the product later. You will have to substitute your System Map address. I have code that does it, i will post it laster too. The inode is the number of a file I was testing, it is really unneeded, but it was good for testing purposes. Right now how 'bout some working code:


/****************************************************************************** 
 * Name: mod.c
 * Info: A few system call hijackings for a Linux Kernel 2.6 LKM.
 *
 * Usage: insmod mod.ko && tail /var/log/messages 
 *
 * Compile: Use Makefile
 * Makefile
 *
 * obj-m += mod.o
 * compile:
 *      make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
 * clean:
 * 	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
 * 
 *
 *
 ******************************************************************************/ 

#include < linux/module.h > 
#include < linux/kernel.h > 
#include < linux/init.h > 
#include < asm/unistd.h > 
#include < linux/syscalls.h >		// sys_close

MODULE_LICENSE("GPL"); 

void **sys_call_table; 

// -----------------------------------------------------------------------------
// Sys Call Table Address 
// -----------------------------------------------------------------------------
unsigned long **find_sys_call_table(void) 
{
   unsigned long **sctable;
   unsigned long ptr;
   extern int loops_per_jiffy;

   sctable = NULL;
   for (ptr = (unsigned long)&loops_per_jiffy;
        ptr < (unsigned long)&boot_cpu_data; 
        ptr += sizeof(void *))
   {
      unsigned long *p;
      p = (unsigned long *)ptr;
      if (p[__NR_close] == (unsigned long) sys_close)
      {
         sctable = (unsigned long **)p;
         return &sctable[0];
      }
   }
   return NULL;
}


// -----------------------------------------------------------------------------
// WRITE
// -----------------------------------------------------------------------------
asmlinkage int (*o_write) (int fd, const void *buf, size_t count); 
asmlinkage int my_write(int fd, const void *buf, size_t count) 
{ 
   int r;
   printk(KERN_INFO "Syscall WRITE Hijacked\n"); 
   r = o_write(fd, buf, count); 
   return r;
} 



// -----------------------------------------------------------------------------
// UNLINK
// -----------------------------------------------------------------------------
asmlinkage int (*o_unlink) (const char *pathname); 
asmlinkage int my_unlink(const char *pathname) 
{ 
   int r;
   printk(KERN_INFO "Syscall UNLINK Hijacked\n"); 
   r = o_unlink(pathname); 
   return r;
} 



// -----------------------------------------------------------------------------
// CHMOD
// -----------------------------------------------------------------------------
asmlinkage int (*o_chmod) (const char *filename, mode_t mode); 
asmlinkage int my_chmod(const char *filename, mode_t mode)
{
   int r;
   printk(KERN_INFO "Syscall CHMOD Hijacked\n"); 
   r = o_chmod(filename, mode);
   return r;
}



// -----------------------------------------------------------------------------
// READ
// -----------------------------------------------------------------------------
asmlinkage int (*o_read) (int fd, void *buf, size_t count);
asmlinkage int my_read(int fd, void *buf, size_t count)
{
   int r;
   printk(KERN_INFO "Syscall READ Hijacked\n"); 
   r = o_read(fd, buf, count);
   return r;
}



// -----------------------------------------------------------------------------
// INIT
// -----------------------------------------------------------------------------
static int __init init_lkm (void) 
{ 
   sys_call_table = find_sys_call_table();
   if (sys_call_table == NULL)
   {
      printk(KERN_ERR "Cannot find the system call address\n"); 
      return -1;  // do not load
   }

   //WRITE
   o_write = (int(*)(int fd, const void *buf, size_t count))(sys_call_table[__NR_write]); 
   sys_call_table[__NR_write] = (unsigned long) my_write; 

   //UNLINK
   //o_unlink = (int(*)(const char *pathname))(sys_call_table[__NR_unlink]); 
   //sys_call_table[__NR_unlink] = (unsigned long) my_unlink; 

   //CHMOD
   //o_chmod = (int(*)(const char *filename, mode_t mode))(sys_call_table[__NR_chmod]); 
   //sys_call_table[__NR_chmod] = (unsigned long) my_chmod; 

   //READ
   //o_read = (int(*)(int fd, void *buf, size_t count))(sys_call_table[__NR_read]); 
   //sys_call_table[__NR_read] = (unsigned long) my_read; 

   return 0; 
} 



// -----------------------------------------------------------------------------
// EXIT
// -----------------------------------------------------------------------------
static void __exit exit_lkm (void) 
{ 
   //WRITE
   sys_call_table[__NR_write] = (unsigned long) o_write; 

   //UNLINK
   //sys_call_table[__NR_unlink] = (unsigned long) o_unlink; 

   //CHMOD
   //sys_call_table[__NR_chmod] = (unsigned long) o_chmod; 

   //READ
   //sys_call_table[__NR_read] = (unsigned long) o_read; 
} 

module_init (init_lkm); 
module_exit (exit_lkm); 

WRONG

KesheR (not verified)
on
June 21, 2006 - 7:36pm

THIS CODE DOESN'T MAKE SENSE IN LATEST KERNEL RELEASES. Just because loops_per_jiffy has been "moved", so sys_call_table is not between it and boot_cpu_data any more.

Finding the Linux System Call table in recent 2.6 series kernels

Charles Hooper (not verified)
on
March 29, 2008 - 6:14pm

Thanks for this! I took a look at my System.map for version 2.6.18 and found that searching between unlock_kernel and loops_per_jiffy worked, so you can probably use these in more recent versions of the 2.6 kernel. You can read more about it in this small article I wrote, Finding the Linux System Call table in 2.6 series kernels.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.