您好,登錄后才能下訂單哦!
這篇文章主要講解了“Linux操作系統(tǒng)下隱藏文件的方法”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Linux操作系統(tǒng)下隱藏文件的方法”吧!
一. 概述
目前通用的隱藏文件方法還是hooksys_getdents64系統(tǒng)調(diào)用, 大致流程就是先調(diào)用原始的sys_getdents64系統(tǒng)調(diào)用,然后在在buf中做過濾。修改sys_call_table是比較原始的rk技術(shù)了,碰到好點的管理員, 基本上gdb一下vmlinux就能檢測出來。 如何想做到更加隱蔽的話,就要尋找新的技術(shù)。 inline hook也是目前比較流行的做法,不容易檢測。本文通過講解一種利用inline hook內(nèi)核中某函數(shù), 來達到隱藏文件的方法。
二. 剖析sys_getdnts64系統(tǒng)調(diào)用
想隱藏文件, 還是要從sys_dents64系統(tǒng)調(diào)用下手。 去看下它在內(nèi)核中是如何實現(xiàn)的。
代碼在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; } |
首先調(diào)用access_ok來驗證是下用戶空間的dirent地址是否越界,是否可寫。 接著根據(jù)fd,利用fget找到對應(yīng)的file結(jié)構(gòu)。 接著出現(xiàn)了一個填充buf數(shù)據(jù)結(jié)構(gòu)的操作,先不管它是干什么的,接著往下看。
vfs_readdir(file, filldir64, &buf);
函數(shù)最終還是調(diào)用vfs層的vfs_readdir來獲取文件列表的。 到這,我們可以是否通過hookvfs_readdir來達到隱藏文件的效果呢。 繼續(xù)跟蹤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個參數(shù),***個是通過fget得到的file結(jié)構(gòu)指針, 第2個通過結(jié)合上下文可得知,這是一個回調(diào)函數(shù)用來填充第3個參數(shù)開始的用戶空間的指針。 接著看看它具體是怎么實現(xiàn)的。
通過security_file_permission()驗證后, 在用mutex_lock_killable()對inode結(jié)構(gòu)加了鎖。然后調(diào)用ile->f_op->readdir(file, buf, filler);通過進一步的底層函數(shù)來對buf進行填充。這個buf就是用戶空間strcut dirent64結(jié)構(gòu)的開始地址。
所以到這里我們可以斷定通過hook vfs_readdir函數(shù)對buf做過濾還是可以完成隱藏文件的功能。而且vfs_readdir的地址是導(dǎo)出的, 這樣就不用復(fù)雜的方法找它的地址了。
但是還有沒有更進一步的方法呢? 前面不是提到過有個filldir64函數(shù)嗎, 它用來填充buf結(jié)構(gòu)的。也許通過hook它來做更隱蔽的隱藏文件方法。 繼續(xù)跟蹤filldir64,看看它是怎么實現(xiàn)的。
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; } |
先把參數(shù)buf轉(zhuǎn)換成struct getdents_callback64的結(jié)構(gòu)指針。
struct getdents_callback64 { struct linux_dirent64 __user * current_dir; struct linux_dirent64 __user * previous; int count; int error; }; |
current_dir始終指向當(dāng)前的struct dirent64結(jié)構(gòu),filldir64每次只填充一個dirent64結(jié)構(gòu)。
它是被file->f_op->readdir循環(huán)調(diào)用的。 通過代碼可以看出是把dirent64結(jié)構(gòu)的相關(guān)項拷貝到用戶空間的dirent64結(jié)構(gòu)中, 然后更新相應(yīng)的指針。
所以通過分析filldir64代碼, 可以判定通過判斷參數(shù)name,看它是否是我們想隱藏的文件,是的話,return 0就好了。
三. 擴展
通過分析sys_getdents64代碼的實現(xiàn),我們可以了解到通過hook內(nèi)核函數(shù)的方法,來完成rootkit的功能是很簡單和方便的。 關(guān)鍵你能了解它的實現(xiàn)邏輯。 對linux平臺來說,閱讀內(nèi)核源代碼是開發(fā)rootkit的根本。 如何hook? 最簡單的就是修改函數(shù)的前幾個字節(jié),jmp到我們的新函數(shù)中去, 在新函數(shù)完成類似函數(shù)的功能。 根本不必在跳回原函數(shù)了, 有了內(nèi)核源代碼在手,原函數(shù)怎么實現(xiàn),我們就怎么copy過去給它在實現(xiàn)一次。 所在linux實現(xiàn)rk也有很方便的一點,就是它的內(nèi)核源代碼是公開的, 好好閱讀源代碼吧, 你會有更多的收獲。
感謝各位的閱讀,以上就是“Linux操作系統(tǒng)下隱藏文件的方法”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Linux操作系統(tǒng)下隱藏文件的方法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。