Chinaunix首页 | 论坛 | 博客
  • 博客访问: 376077
  • 博文数量: 81
  • 博客积分: 4016
  • 博客等级: 上校
  • 技术积分: 800
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-17 18:38
文章分类

全部博文(81)

文章存档

2016年(5)

2015年(2)

2010年(1)

2008年(1)

2007年(4)

2006年(68)

我的朋友

分类: LINUX

2006-03-29 19:00:55

Finding hidden kernel modules (the extrem way)
        --------by madsys

1 Introduction
2 The technique of module hiding
3 Countermeasure -- brute force
4 Problem of unmapped
5 Greetings
6 References
7 Code

1 Introduction

This paper presents a method for how to find out the hidden modules in

linux system. Generaly speaking, most of the attackers intend to hide

their modules after taking down the victim. They like this way to prevent

the change of kernel from being detected by the administrator. As modules

were linked to a singly linked chain, the original one was unable to be

recovered while some modules have been removed. In this sense, to retrieve

the hidden modules came up to be hard. Essential C skill and primary

knowledge of linux kernel are needed.


2 The technique of module hiding

First of all, the most popular and general technique of module hiding

and the quomodo of application to get module's list were examined.

An implement of module hiding was shown as below:



    ----snip----

    struct module *p;

   

    for (p=&__this_module; p->next; p=p->next)

        {

            if (strcmp(p->next->name, str))

                continue;

            p->next=p->next->next;        // <-- here it

removes that module

                break;

        }

   

    ----snip----



As you can see, in order to hide one module, the unidirectional chain was

modified, and following is a snippet of sys_create_module() system call,

which might tell why the technique worked:



    ----snip----

    spin_lock_irqsave(&modlist_lock, flags);

    mod->next = module_list;

    module_list = mod;    /* link it in */

    spin_unlock_irqrestore(&modlist_lock, flags);

    ----snip----



A conclusion could be made: modules linked to the end of unidirectional

chain when they were created.



"lsmod" is an application on linux for listing current loaded modules,

which uses sys_query_module() system call to get the listing of loaded

modules, and qm_modules() is the actual function called by it while

querying modules:





static int qm_modules(char *buf, size_t bufsize, size_t *ret)

{

    struct module *mod;

    size_t nmod, space, len;



    nmod = space = 0;



    for (mod=module_list; mod != &kernel_module; mod=mod->next,

++nmod) {

        len = strlen(mod->name)+1;

        if (len > bufsize)

            goto calc_space_needed;

        if (copy_to_user(buf, mod->name, len))

            return -EFAULT;

        buf += len;

        bufsize -= len;

        space += len;

    }



    if (put_user(nmod, ret))

        return -EFAULT;

    else

        return 0;



calc_space_needed:

    space += len;

    while ((mod = mod->next) != &kernel_module)

        space += strlen(mod->name)+1;



    if (put_user(space, ret))

        return -EFAULT;

    else

        return -ENOSPC;

}



    note: pointer module_list is always at the head of the singly linked

chain. It clearly showing the technique of hiding module was valid.





3 Countermeasure -- brute force

===============================



According to the technique of hiding module, brute force might be useful.

sys_creat_module() system call was expressed as below.



    --snip--

    if ((mod = (struct module *)module_map(size)) == NULL) {

        error = -ENOMEM;

        goto err1;

    }

    --snip--



    and the macro module_map in "asm/module.h":

    #define module_map(x)    vmalloc(x)





You should have noticed that the function calls vmalloc() to allocate the

module struct. So the size limitation of vmalloc zone for brute force is

able to be exploited to determine what modules in our system on earth.

As you know, the vmalloc zone is 128M(2.2, 2.4 kernel, there are many

inanition zones in it), however, any allocated module should be aligned by

4K. Therefor, the theoretical maximum number we were supposed to detect

was 128M/4k=32768.



4 Problem of unmapped

=====================



By far, maybe you think: umm, it's very easy to use brute force to list

those evil modules". But it is not true because of an important

reason: it is possible that the address which you are accessing is

unmapped, thus it can cause a paging fault and the kernel would report:

"Unable to handle kernel paging request at virtual address".



So we must make sure the address we are accessing is mapped. The solution

is to verify the validity of the corresponding entry in kernel

pgd(swapper_pg_dir) and the corresponding entry in page table.Furthermore,

we were supposed to make sure the content of address pointed by "name"

pointer(in struct module) was valid. Because the 768~1024 entries of user

process's pgd were synchronous with kerenl pgd, and that was why such

hardcore address of kernel pgd (0xc0101000) was used.





following is the function for validating those entries in pgd or pgt:



int valid_addr(unsigned long address)

{

    unsigned long page;



    if (!address)

        return 0;



    page = ((unsigned long *)0xc0101000)[address >> 22];       

//pde

    if (page & 1)

    {

        page &= PAGE_MASK;

        address &= 0x003ff000;

        page = ((unsigned long *) __va(page))[address >>

PAGE_SHIFT];    //pte

        if (page)

            return 1;

    }

   

    return 0;

}



After validating those addresses which we would check, the next step would

be easy -- just brute force. As the list of modules including hidden

modules had been created, you could compare it with the output of "lsmod".

Then you can find out those evil modules and get rid of them freely.





5 Greetings

===========



Shout to





6 Code

======



-----BEGING MODULE_HUNTER.C-----

/*

* module_hunter.c: Search for patterns in the kernel address space that

* look like module structures. This tools find hidden modules that

* unlinked themself from the chained list of loaded modules.

*

* This tool is currently implemented as a module but can be easily ported

* to a userland application (using /dev/kmem).

*

* Compile with: gcc -c module_hunter.c -I/usr/src/linux/include

* insmod ./module_hunter.o

*

* usage: cat /proc/showmodules && dmesg

*/



#define MODULE

#define __KERNEL__



#include



#ifdef CONFIG_SMP

#define __SMP__

#endif



#ifdef CONFIG_MODVERSIONS

#define MODVERSIONS

#include

#endif



#include

#include

#include



#include

#include





#include



#include

#include





#include

#include

#include



static int errno;





int valid_addr(unsigned long address)

{

    unsigned long page;



    if (!address)

        return 0;



    page = ((unsigned long *)0xc0101000)[address >> 22];       



    if (page & 1)

    {

        page &= PAGE_MASK;

        address &= 0x003ff000;

page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; //pte
        if (page)

            return 1;

    }

   

    return 0;

}



ssize_t

showmodule_read(struct file *unused_file, char *buffer, size_t len, loff_t *off)

{

    struct module *p;



    printk("address                         module\n\n");

    for (p=(struct module *)VMALLOC_START; p<=(struct \

module*)(VMALLOC_START+VMALLOC_RESERVE-PAGE_SIZE); p=(struct module \

*)((unsigned long)p+PAGE_SIZE))

    {

        if (valid_addr((unsigned long)p+ (unsigned long)&((struct \

module *)NULL)->name) && valid_addr(*(unsigned long *)((unsigned long)p+ \

(unsigned long)&((struct module *)NULL)->name)) && strlen(p->name))

            if (*p->name>=0x21 && *p->name<=0x7e &&
(p->size < 1 <<20))

                printk("0x%p%20s size: 0x%x\n", p, p->name, p->size);

    }



    return 0;

}



static struct file_operations showmodules_ops = {

    read:    showmodule_read,

};



int init_module(int x)

{

    struct proc_dir_entry *entry;



    entry = create_proc_entry("showmodules", S_IRUSR, &proc_root);

    entry->proc_fops = &showmodules_ops;



    return 0;

}



void cleanup_module()

{

    remove_proc_entry("showmodules", &proc_root);

}



MODULE_LICENSE("GPL");

MODULE_AUTHOR("madsysercist.iscas.ac.cn");

-----END MODULE-HUNTER.C-----
阅读(1075) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~