A New Method for hiding files in Linux
Author: wzt
EMail: wzt@xsec.org
Site: http://www.xsec.org & http://hi.baidu.com/wzt85
Date: 2008-9-23
I. Overview
Currently, the common method for hiding files is hooksys_getdents64 system call. The general process is to call the original
Sys_getdents64 is called by the system and then filtered in the buf. Modifying sys_call_table is a primitive rk technology,
When it comes to a better administrator, it is basically possible to detect it in gdb vmlinux. To be more concealed
Find new technologies. Inline hook is also a popular practice and is not easy to detect. This article explains a usage
A function in the inline hook kernel to hide files.
2. Analyze sys_getdnts64 system calls
To hide a file, you still need to start with sys_dents64 system call. Let's see how it is implemented in the kernel.
Code in linux-2.6.26/fs/readdir. c:
Asmlinkage long sys_getdents64 (unsigned int fd, struct linux_di1_64 _ user * dirent, unsigned int count)
{
Struct file * file;
Struct linux_di1_64 _ 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;
}
First, call access_ OK to verify whether the dirent address of the user space is out of bounds and writable. Then, based on fd,
Use fget to find the corresponding file structure. Then there is an operation to fill the buf data structure, no matter what it is,
Next, let's look at it.
Vfs_readdir (file, filldir64, & buf );
The function finally calls vfs_readdir at the vfs layer to obtain the file list. At this point, can we use the hook
Vfs_readdir to hide files. Continue to follow vfs_readdir to see if this idea is feasible.
The source code is in the same file:
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 );
It has three parameters. The first one is the file structure pointer obtained through fget, and the first one is known by combining context. This is
The callback function is used to populate the pointer of the user space starting with 3rd parameters. Next, let's see how it is implemented.
After security_file_permission () verification, the inode structure is locked with mutex_lock_killable.
Then, call ile-> f_op-> readdir (file, buf, filler) to fill the buf with further underlying functions.
This buf is the starting address of the strcut di1_64 structure of the user space.
So here we can determine whether the function of filtering the buf through the hook vfs_readdir function can complete the function of hiding files.
In addition, the vfs_readdir address is exported, so that you do not need to find its address in a complicated way.
But is there any further way? Didn't I mention a filldir64 function, which is used to fill the buf structure.
You may use the hook to hide a file more concealed. Continue to track filldir64 to see how it is implemented.
Static int filldir64 (void * _ buf, const char * name, int namlen, loff_t offset,
U64 ino, unsigned int d_type)
{
Struct linux_di1_64 _ 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 ))
&