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
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
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.