想必能找到这里的都是被吴一民的操作系统大作业坑过的学弟学妹了,当初我也是千辛万苦才把这个作业完成了,本着服务后辈的宗旨,尽量让学弟学妹少走弯路,我会把实现的大概思路记录下来。本系列一共三篇文章,分别实现了三种进程隐藏的方法。
- 实验目标
ps和top命令列出了unix中当前所有进程的相关信息,作业要求在linux中增加两个系统调用,功能如下:
hide():执行此系统调用后,隐藏当前进程,即当前进程不能够被ps和top命令查看到。
unhide():执行此系统调用后,取消隐藏当前进程,即当前进程恢复正常,能够被ps和top命令查看到。
- 实验解题思路
1.修改linux的进程控制块task_struts,在进程控制块中增加一个字段:
int hide;
hide的值为1时,表示该进程被隐藏;为0时,表示该进程不被隐藏。
2.修改创建进程的相关代码,在进程创建时,置hide为0;即进程在初始创建时(默认)不被隐藏。
3.在系统中增加系统调用hide(),其功能为:
1)将进程控制块中的hide置1;
2)删除/proc文件系统中该进程的相关目录项;
4.在系统中增加系统调用unhide(),其功能为:
1)将进程控制块中的hide清0;
2)增加/proc文件系统中该进程的相关目录项
这里是三种方法的共同步骤,包括修改task_struct,修改进程创建代码,添加系统调用,重新编译内核。
首先修改task_struct
在struct task_struct(includelinuxsched.h)的定义中加入hide字段:
接着修改linux创建进程的代码,找到kernel/fork.c,通过阅读代码可以发现,fork()调用了do_fork(),而do_fork()又调用了copy_process(),copy_process()函数的作用是将父进程的进程描述符(即task_struct)拷贝给子进程,在该函数中加入对hide字段的初始化:
下一步是添加系统调用:
1.修改include/asm-generic/unistd.h,分配系统调用号
加入新的系统调用,同时将__NR_syscalls的值由273改为275
2.修改系统调用表
修改arch/x86/syscalls/syscall_64.tbl文件,根据原有表内容的格式,在322行处添加如下内容
3.添加处理函数
在源代码目录下,创建hide文件夹,新建hide.c文件与unhide.c文件。
hide.c的代码如下所示:
unhide.c的代码如下所示:
编写编译这两个文件进内核模块的Makefile:
接着在编译内核的Makefile中的core-y字段中加入编译刚才新建的两个系统调用的Makefile所在的路径:
添加系统调用后注意需要重新编译内核,以使改动生效。
方法一:
本文通过修改proc文件系统读取进程文件的函数proc_pid_readdir,在其中加入对进程hide字段的判断来实现隐藏进程。
跟踪内核可知,proc目录下进程号目录是动态生成的,是在每次readdir,getdents时动态生成,所以从某种意义上说增加或删除/proc文件系统中该进程的相关目录项这种说法是不正确的。proc目录内容的填充函数是proc_pid_readdir(fs/proc/base.c),因此我们只要修改proc_pid_readdir函数的代码,加上对要隐藏进程的判断就可以实现隐藏进程的目的。
proc_pid_readdir的定义如下:
/* for the /proc/ directory itself, after non-process stuff has been done */ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) { unsigned int nr; struct task_struct *reaper; struct tgid_iter iter; struct pid_namespace *ns; filldir_t __filldir; ........................ for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) { //填充self目录 const struct pid_entry *p = &proc_base_stuff[nr]; if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0) goto out; } ns = filp->f_dentry->d_sb->s_fs_info; iter.task = NULL; iter.tgid = filp->f_pos - TGID_OFFSET; /* 遍历进程散列表,向proc目录填充进程目录项,是我们要修改的地方 */ for (iter = next_tgid(ns, iter); iter.task; iter.tgid += 1, iter = next_tgid(ns, iter)) { if (has_pid_permissions(ns, iter.task, 2)) __filldir = filldir; else __filldir = fake_filldir; filp->f_pos = iter.tgid + TGID_OFFSET; if (proc_pid_fill_cache(filp, dirent, __filldir, iter) < 0) { put_task_struct(iter.task); goto out; } } filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET; out: put_task_struct(reaper); out_no_task: return 0; }
接着执行make menuconfig选择要编译的模块,然后make -j10开10个线程进行编译,编译完成后make modules_install
测试程序:
结果: