歡迎您光臨本站 註冊首頁

分享:Linux操作系統下隱藏文件

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0

一. 概述

目前通用的隱藏文件方法還是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來獲取文件列表的. 到這,我們可以是否通過hookvfs_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))       goto efault;       if (__put_user(reclen, &dirent->d_reclen))       goto efault;       if (__put_user(d_type, &dirent->d_type))       goto efault;       if (copy_to_user(dirent->d_name, name, namlen))       goto efault;       if (__put_user(0, dirent->d_name   namlen))       goto efault;       buf->previous = dirent;       dirent = (void __user *)dirent   reclen;       buf->current_dir = dirent;       buf->count -= reclen;       return 0;       efault:       buf->error = -EFAULT;       return -EFAULT;       }


先把參數buf轉換成struct getdents_callback64的結構指針.

struct getdents_callback64 {       struct linux_dirent64 __user * current_dir;       struct linux_dirent64 __user * previous;       int count;       int error;       };


current_dir始終指向當前的struct dirent64結構,filldir64每次只填充一個dirent64結構.

它是被file->f_op->readdir循環調用的. 通過代碼可以看出是把dirent64結構的相關項拷貝到用戶空間的dirent64結構中, 然後更新相應的指針.

通過分析filldir64代碼, 可以判定通過判斷參數name,看它是否是我們想隱藏的文件,是的話,return 0就好了.

三. 擴展

通過分析sys_getdents64代碼的實現,我們可以了解到通過hook內核函數的方法,來完成rootkit的功能是很簡單和方便的. 關鍵你能了解它的實現邏輯. 對linux平台來說,閱讀內核源代碼是開發rootkit的根本. 如何hook? 最簡單的就是修改函數的前幾個位元組,jmp到我們的新函數中去, 在新函數完成類似函數的功能. 根本不必在跳回原函數了, 有了內核源代碼在手,原函數怎麼實現,我們就怎麼copy過去給它在實現一次. 所在linux實現rk也有很方便的一點,就是它的內核源代碼是公開的, 好好閱讀源代碼吧, 你會有更多的收穫.


[火星人 ] 分享:Linux操作系統下隱藏文件已經有879次圍觀

http://coctec.com/docs/linux/show-post-53452.html