一种Linux下隐藏文件的新方法


一种Linux下隐藏文件的新方法
       
Author: wzt
EMail: wzt@xsec.org
Site: http://www.xsec.org & http://hi.baidu.com/wzt85
Date: 2008-9-23

一. 概述

目前通用的隐藏文件方法还是hooksys_getdents64系统调用, 大致流程就是先调用原始的
sys_getdents64系统调用,然后在在buf中做过滤。修改sys_call_table是比较原始的rk技术了,
碰到好点的管理员, 基本上gdb一下vmlinux就能检测出来。 如何想做到更加隐蔽的话,就要
寻找新的技术。 inline hook也是目前比较流行的做法,不容易检测。本文通过讲解一种利用
inline hook内核中某函数, 来达到隐藏文件的方法。

二. 剖析sys_getdnts64系统调用
想隐藏文件, 还是要从sys_dents64系统调用下手。 去看下它在内核中是如何实现的。
代码在linux-2.6.26/fs/readdir.c中:

asmlinkage long sys_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent, unsigned int count)
{
        struct file * file;
        struct linux_dirent64 __user * lastdirent;
        struct getdents_callback64 buf;
        int error;

        error = -EFAULT;
        if (!access_ok(VERIFY_WRITE, dirent, count))
                goto out;

        error = -EBADF;
        file = fget(fd);
        if (!file)
                goto out;

        buf.current_dir = dirent;
        buf.previous = NULL;
        buf.count = count;
        buf.error = 0;

        error = vfs_readdir(file, filldir64, &buf);
        if (error < 0)
                goto out_putf;
        error = buf.error;
        lastdirent = buf.previous;
        if (lastdirent) {
                typeof(lastdirent->d_off) d_off = file->f_pos;
                error = -EFAULT;
                if (__put_user(d_off, &lastdirent->d_off))
                        goto out_putf;
                error = count - buf.count;
        }

out_putf:
        fput(file);
out:
        return error;
}

首先调用access_ok来验证是下用户空间的dirent地址是否越界,是否可写。 接着根据fd,
利用fget找到对应的file结构。 接着出现了一个填充buf数据结构的操作,先不管它是干什么的,
接着往下看。
vfs_readdir(file, filldir64, &buf);
函数最终还是调用vfs层的vfs_readdir来获取文件列表的。 到这,我们可以是否通过hook
vfs_readdir来达到隐藏文件的效果呢。 继续跟踪vfs_readdir看看这个想法是否可行。

源代码在同一文件中:

int vfs_readdir(struct file *file, filldir_t filler, void *buf)
{
        struct inode *inode = file->f_path.dentry->d_inode;
        int res = -ENOTDIR;
        if (!file->f_op || !file->f_op->readdir)
                goto out;

        res = security_file_permission(file, MAY_READ);
        if (res)
                goto out;

        res = mutex_lock_killable(&inode->i_mutex);
        if (res)
                goto out;

        res = -ENOENT;
        if (!IS_DEADDIR(inode)) {
                res = file->f_op->readdir(file, buf, filler);
                file_accessed(file);
        }
        mutex_unlock(&inode->i_mutex);
out:
        return res;
}

EXPORT_SYMBOL(vfs_readdir);

它有3个参数,第一个是通过fget得到的file结构指针, 第2个通过结合上下文可得知,这是一个
回调函数用来填充第3个参数开始的用户空间的指针。 接着看看它具体是怎么实现的。
通过security_file_permission()验证后, 在用mutex_lock_killable()对inode结构加了锁。
然后调用ile->f_op->readdir(file, buf, filler);通过进一步的底层函数来对buf进行填充。
这个buf就是用户空间strcut dirent64结构的开始地址。

所以到这里我们可以断定通过hook vfs_readdir函数对buf做过滤还是可以完成隐藏文件的功能。
而且vfs_readdir的地址是导出的, 这样就不用复杂的方法找它的地址了。

但是还有没有更进一步的方法呢? 前面不是提到过有个filldir64函数吗, 它用来填充buf结构的。
也许通过hook它来做更隐蔽的隐藏文件方法。 继续跟踪filldir64,看看它是怎么实现的。

static int filldir64(void * __buf, const char * name, int namlen, loff_t offset,
                     u64 ino, unsigned int d_type)
{
        struct linux_dirent64 __user *dirent;
        struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf;
        int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 1, sizeof(u64));

        buf->error = -EINVAL;
        if (reclen > buf->count)
                return -EINVAL;
        dirent = buf->previous;
        if (dirent) {
                if (__put_user(offset, &dirent->d_off))
                        goto efault;
        }
        dirent = buf->current_dir;
        if (__put_user(ino, &dirent->d_ino))
                goto efault;
        if (__put_user(0, &dirent->d_off))
             &

相关内容

    暂无相关文章