ls的功能是列出目录中的内容,通过ls命令隐藏后门是最简单基本的rootkit。
磁盘上的文件系统由文件和目录组成,文件的内容可以是任意的数据,而目录的内容只能是文件名的列表和子目录名的列表,目录中的内容是该目录下的文件和子目录它们的名字的列表。
先来看一看关于目录的结构体
/usr/include/bits/dirent.h
struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* offset to the next dirent */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supportedby all file system types */ char d_name[256]; /* filename */ };
d_ino是目录中的文件的i-node节点号,通过d_ino可以找到该文件的i-node节点,而i-node节点中保存了文件的属性等信息。通过i-node节点就可以访问到文件的内容。
关于目录访问的一些函数
/usr/include/dirent.h
#include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name); DIR *fdopendir(int fd); struct dirent *readdir(DIR *dirp); int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); int closedir(DIR *dirp); void rewinddir(DIR *dirp);
关于目录中文件的属性等信息使用struct stat结构体来描述的,其结构的定义如下
/usr/include/bits/stat.h
struct stat { __dev_t st_dev; /* Device. */ unsigned short int __pad1; /* 用于填充对齐 */ __ino_t st_ino; /* 32bit file serial number. */ __mode_t st_mode; /* File mode. */ __nlink_t st_nlink; /* Link count. */ __uid_t st_uid; /* User ID of the file's owner. */ __gid_t st_gid; /* Group ID of the file's group.*/ __dev_t st_rdev; /* Device number, if device. */ unsigned short int __pad2; /* 用于填充对齐 */ __off_t st_size; /* Size of file, in bytes. */ __blksize_t st_blksize; /* Optimal block size for I/O. */ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ struct timespec st_atim; /* Time of last access. */ struct timespec st_mtim; /* Time of last modification. */ struct timespec st_ctim; /* Time of last status change. */ # define st_atime st_atim.tv_sec /* Backward compatibility. */ # define st_mtime st_mtim.tv_sec # define st_ctime st_ctim.tv_sec __ino64_t st_ino; /* File serial number. */ };
该结构体提供了关于文件(或者设备)的如下重要信息:
st_mode | 文件类型和许可权限 |
st_nlink | 文件链接数 |
st_uid | 文件属主id |
st_gid | 文件属主所在组的id |
st_size | 文件的字节数 |
st_blocks | 文件所占的块数 |
“ACM”三个时间:
st_atime | 文件最后访问时间 | access time |
st_mtime | 文件最后修改时间 | modification time |
st_ctime | 文件属性/状态最后改变的时间 | change status time |
另外在/usr/include/sys/stat.h中提供了下列关于文件信息的宏定义
/usr/include/sys/stat.h
typedef __dev_t dev_t; typedef __gid_t gid_t; typedef __ino_t ino_t; typedef __mode_t mode_t; typedef __nlink_t nlink_t; typedef __off_t off_t; typedef __uid_t uid_t; typedef __blkcnt_t blkcnt_t; typedef __blksize_t blksize_t; /* Test macros for file types. */ #define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask)) #define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR) // directory 目录文件类型 #define S_ISCHR(mode) __S_ISTYPE((mode), __S_IFCHR) // char 字文件类型 #define S_ISBLK(mode) __S_ISTYPE((mode), __S_IFBLK) // block 块文件类型 #define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG) // regular 普通文件类型 #define S_ISFIFO(mode) __S_ISTYPE((mode), __S_IFIFO) // FIFO 管道文件类型 #define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK) // link 链接文件类型 #define S_ISSOCK(mode) __S_ISTYPE((mode), __S_IFSOCK) // sock 网络套接字文件类型 /* Protection bits. */ #define S_ISUID __S_ISUID /* Set user ID on execution. */ #define S_ISGID __S_ISGID /* Set group ID on execution. */ #define S_IRUSR __S_IREAD /* Read by owner. */ #define S_IWUSR __S_IWRITE /* Write by owner. */ #define S_IXUSR __S_IEXEC /* Execute by owner. */ /* Read, write, and execute by owner. */ #define S_IRWXU (__S_IREAD|__S_IWRITE|__S_IEXEC) #define S_IRGRP (S_IRUSR >> 3) /* Read by group. */ #define S_IWGRP (S_IWUSR >> 3) /* Write by group. */ #define S_IXGRP (S_IXUSR >> 3) /* Execute by group. */ /* Read, write, and execute by group. */ #define S_IRWXG (S_IRWXU >> 3) #define S_IROTH (S_IRGRP >> 3) /* Read by others. */ #define S_IWOTH (S_IWGRP >> 3) /* Write by others. */ #define S_IXOTH (S_IXGRP >> 3) /* Execute by others. */ /* Read, write, and execute by others. */ #define S_IRWXO (S_IRWXG >> 3) # define S_BLKSIZE 512 /* Block size for `st_blocks'. */
有了上面的基础,实现代码如下:
#include <stdio.h> #include <sys/types.h> #include <dirent.h> #include <sys/stat.h> #include <string.h> #include <time.h> #include <pwd.h> #include <grp.h> void do_ls(char[]); void do_stat(char*); void show_file_info(char*, struct stat*); void mode_str(int, char[]); char *uid_str(uid_t); char *gid_str(gid_t); int main(int argc, char *argv[]) { if(argc == 1) do_ls("."); else while(--argc){ printf("%s:\n", *++argv); do_ls(*argv); } return 0; } void do_ls(char dirname[]) { DIR *dir_ptr; /* the directory */ struct dirent *direntp; /* each entry */ char full_path[256]; if((dir_ptr = opendir(dirname)) == NULL){ fprintf(stderr, "ls2: cannot open %s\n", dirname); }else{ while((direntp = readdir(dir_ptr)) != NULL){ strcpy(full_path, dirname); int dir_len = strlen(dirname); if(dirname[dir_len - 1] != '/'){ /* 处理目录字符串最后没有‘/’的情况 */ full_path[dir_len] = '/'; strcpy(full_path + dir_len + 1, direntp->d_name); }else strcpy(full_path + dir_len, direntp->d_name); do_stat(full_path); } closedir(dir_ptr); } } void do_stat(char *filename) /* 获得目录中文件的相关信息 */ { struct stat info; /* 如果filename最后没有‘/’的话,stat调用失败 */ if(stat(filename, &info) == -1){ /* cannot stat */ perror("stat"); /* say why */ printf("filename:%s\n", filename); }else{ char *pname = strrchr(filename, '/'); show_file_info(pname + 1, &info); } } void show_file_info(char *filename, struct stat *info_p) /* 打印文件的相关信息 */ { char modestr[11]; mode_str(info_p->st_mode, modestr); printf("%s", modestr); printf("%3d ", (int)info_p->st_nlink); printf("%-8s", uid_str(info_p->st_uid)); printf("%-8s", gid_str(info_p->st_gid)); printf("%4ld ", (long)info_p->st_size); printf("%.12s ", 4 + ctime(&info_p->st_mtime)); printf("%s\n", filename); } void mode_str(int mode, char str[]) /* 将文件的相关信息转化成 “crw-rw---"的形式 */ { strcpy(str, "----------"); /* default = no perms */ if(S_ISDIR(mode)) str[0] = 'd'; /* directory */ if(S_ISCHR(mode)) str[0] = 'c'; /* char device */ if(S_ISBLK(mode)) str[0] = 'b'; /* block device */ if(S_ISLNK(mode)) str[0] = 'l'; if(mode & S_IRUSR) str[1] = 'r'; /* 3 bits for user */ if(mode & S_IWUSR) str[2] = 'w'; if(mode & S_IXUSR) str[3] = 'x'; if(mode & S_IRGRP) str[4] = 'r'; /* 3 bits for group */ if(mode & S_IWGRP) str[5] = 'w'; if(mode & S_IXGRP) str[6] = 'x'; if(mode & S_IROTH) str[7] = 'r'; /* 3 bits for other */ if(mode & S_IWOTH) str[8] = 'w'; if(mode & S_IXOTH) str[9] = 'x'; } char *uid_str(uid_t uid) /* 将uid转化成username */ { static char numstr[10]; struct passwd *pw_ptr; if((pw_ptr = getpwuid(uid)) == NULL){ sprintf(numstr, "%d", uid); return numstr; }else return pw_ptr->pw_name; } char *gid_str(gid_t gid) /* 将gid转化成groupname */ { static char numstr[10]; struct group *grp_ptr; if((grp_ptr = getgrgid(gid)) == NULL){ sprintf(numstr, "% d", gid); return numstr; }else return grp_ptr->gr_name; }