Fedora7 (linux2.6.21)添加系统调用

一、实验内容

1. 阅读并分析Linux内核源代码,了解进程控制块、进程队列等数据结构;

2. 实现一个系统调用,使得可以根据指定的参数隐藏进程,使用户无法使用ps或top观察到进程状态。具体要求如下:

(1)实现系统调用int hide(pid_t pid, int on),在进程pid有效的前提下,如果on置1,进程被隐藏,用户无法通过ps或top观察到进程状态;如果on置0且此前为隐藏状态,则恢复正常状态。

(2)考虑权限问题,只有根用户才能隐藏进程。

3.设计一个新的系统调用int hide_user_processes(uid_t uid, char *binname),参数uid为用户ID号,当binname参数为NULL时,隐藏该用户的所有进程;否则,隐藏二进制映像名为binname的用户进程。该系统调用应与hide系统调用共存。

4.在/proc目录下创建一个文件/proc/hidden,该文件可读可写,对应一个全局变量hidden_flag,当hidden_flag为0时,所有进程都无法隐藏,即便此前进程被hide系统调用要求隐藏。只有当hidden_flag为1时,此前通过hide调用要求被屏蔽的进程才隐藏起来。

5.在/proc目录下创建一个文件/proc/hidden_process,该文件的内容包含所有被隐藏进程的pid,各pid之间用空格分开。

二、实现

  1. 准备工作与内核编译

使用VMware,下载并安装Fedora7.

su root 切换到根账号

切换下载源

yum install yum-fastestmirror -y  

安装依赖软件包

yum install gcc

yum install gcc-c++

yum -y install ncurces

yum install ncurces-devel

cp将源码移动到/usr/src

[root@localhost /]# cd /home/seu/Desktop

[root@localhost Desktop]# sudo cp linux-2.6.21.tar.gz /usr/src/linux-2.6.21.tar.gz

cd  /usr/src 切换到src

tar -xvf linux-2.6.21.tar.gz

cd linux-2.6.21

利用make命令开始编译内核。

make mrproper     //删除以前垃圾文件

make menuconfig  //直接exit即可

make dep  //建立相依的属性关系

make clean      //去除旧资料

make [-j4] bzImage  //编译内核,多线程加速

make [-j4] modules  //编译模块

make modules_install  //安装模块

make install  //安装内核

reboot  //重启

tip:fedora 重启阶段蓝屏时按空格可以切换内核

  

2.实现隐藏进程的系统调用,并限制用户权限

2.1修改/usr/src/linux-2.6.21/include/linux/sched.h:

[root@localhost include]# cd /usr/src/linux-2.6.21/include/linux

[root@localhost linux]# gedit sched.h

在task_structd的末尾添加变量hide和old_pid。  hide用于表示是否隐藏,old_pid用于保存进程原本的pid,用于进程的恢复。在进程创建的时候对hide进行初始化,这里默认初始化为0,表示不隐藏。

2.2修改/usr/src/linux-2.6.21/kernel/fork.c:

[root@localhost linux]# gedit /usr/src/linux-2.6.21/kernel/fork.c

fork系统调用具体实现的主要函数为do_fork,do_fork中调用copy_process函数创建子进程,将初始化hide的代码添加在copy_process函数中。

2.3修改系统调用sys.c,在文件结尾添加新的系统调用hide和hide_user_process

[root@localhost linux]# gedit /usr/src/linux-2.6.21/kernel/sys.c

考虑用户权限限制,使用全局变量current->uid获取当前用户权限,值为0代表root用户。

2.4修改内核unistd.h,统一系统调用个数。

对于类 Unix 系统,unistd.h 中所定义的接口通常都是大量针对系统调用的封装。

/usr/src/linux-2.6.21/include/asm/unistd.h是内核代码头文件

/usr/include/asm/unistd.h 是标准C库的头文件

检查两个头文件定义的系统调用是否一致,并在/usr/src/linux-2.6.21/include/asm/unistd.h中加上自定义的系统调用hide及hide_user_process。

2.5修改syscall_table,末尾添加新的系统调用

gedit /usr/src/linux-2.6.21/arch/i386/kernel/syscall_table.S

2.6重新编译内核,并测试这两个新的系统调用

3.在/proc目录下创建一个文件/proc/hidden

该文件可读可写,对应一个全局变量hidden_flag,当hidden_flag为0时,所有进程都无法隐藏,即便此前进程被hide系统调用要求隐藏。只有当hidden_flag为1时,此前通过hide调用要求被屏蔽的进程才隐藏起来。

3.0将系统调用移到/proc/base.c下,添加头文件

3.1在fs/proc/proc_misc.c文件中声明全局变量int hidden_flag,EXPORT_SYMBOL()函数可以使该变量在整个内核中可见。使用时只要extern int hidden_flag;即可访问同一变量。

3.2 同文件下,将创建hidden文件的代码插入proc_misc_init()

proc文件系统在初始化函数proc_root_init中会调用proc_misc_init函数,此函数用于创建/proc根目录下的文件,那么将创建hidden文件的代码插入到此函数中就可以在proc初始化时得到执行。

3.3读写hidden文件的回调函数

原型:

typedef int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data);

typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data);

实现:

static int proc_write_hidden(struct file* file, const char *buffer, unsigned long count, void *data)

static int proc_read_hidden(char* page, char** start, off_t off, int count, int *eof, void *data)

当某个进程读取proc文件时,内核会分配一个内存页,内核模块将数据写入到这张页来返回数据到用户空间。

Read:

//page参数是为进程分配的内存页

//count定义了可以写入的最大字符数。

//start+off:在返回多页数据(通常一页是4K),我们需要使用start和off参数。在read_proc_t方法被调用时,*start的初始值为N。

//eof:文件结束参数,当所有数据全部写入后,需要设置eof。

//return:返回写入的字节数。

Write:

//buffer为用户空间需要写入的数据的头指针

//count 为用户空间需要写入内核的数据长度

//data为proc结构体得私有数据,对应于 struct proc_dir_entry结构体中的data字段。

4./proc目录下创建一个文件/proc/hidden_process

    该文件的内容包含所有被隐藏进程的pid,各pid之间用空格分开。类比3的操作,但hidden_process的权限为只读

三、数据结构

(一)进程控制块PCB(task_struct)

Linux中保存进程信息的数据结构叫做 task_struct

/include/sched.h

struct task_struct

{

        volatile long state;  /* -1 unrunnable, 0 runnable, >0 stopped *///进程状态

        struct thread_info *thread_info;

        atomic_t usage;

        unsigned long flags;        /* per process flags, defined below *///进程标记

        unsigned long ptrace;// ptrace被设置为0时表示不需要被跟踪

        int lock_depth;                /* BKL lock depth */

……

#ifdef CONFIG_FAULT_INJECTION

        int make_it_fail;

#endif

        int hide;//是否隐藏进程

        int oid_pid;//保存原pid用于恢复

};

(二)proc文件结构

struct proc_dir_entry {

    unsigned int low_ino;

    unsigned short namelen;

    const char *name;

    mode_t mode;

    nlink_t nlink;

    uid_t uid;

    gid_t gid;

    loff_t size;

    struct inode_operations * proc_iops;

    const struct file_operations * proc_fops;

    get_info_t *get_info;

    struct module *owner;

    struct proc_dir_entry *next, *parent, *subdir;

    void *data;

    read_proc_t *read_proc;//读proc文件函数,实现内核到用户

    write_proc_t *write_proc;//写proc文件函数,实现用户到内核

    atomic_t count;     /* use count */

    int deleted;        /* delete flag */

    void *set;

};

四、源码

(一)fork.c:


修改


添加:

(二)sys.c

文件尾添加两个新的系统调用。由于在ps,top命令中不显示0号进程的相关信息,因此隐藏进程的方法是置pid=0。

系统调用hide:隐藏指定pid的进程

系统调用hide_user_process:按照指定uid或uid和进程名隐藏
 

(三)修改unistd.h,加上新的系统调用


两个文件末尾添加新的系统调用320/321并修改系统调用总数为322

(四)修改syscall_table.S,添加新的系统调用

(五)内核创建proc 文件hidden和hidden_process

声明全局变量:


修改proc_misc_init()

 Create_proc_entry()第一个参数是文件名,第二个参数是文件的读写权限,第三个参数是路径,因为在proc文件的根目录所以为NULL。

对hidden和hiddenprocess的读写函数

#define for_each_process(p) \

        for (p = &init_task ; (p = next_task(p)) != &init_task ; )

(六)修改proc/base.c中的proc_pid_lookup函数及proc_pid_readdir函数,使hidden_flag优先级高于task->hide

(七)修改自定义系统调用逻辑,移动到proc/base.c中,增加调试语句。利用find_task_by_pid()定位进程,代码更简洁。调用函数proc_flush_task来清空VFS层的缓冲,解除已有的dentry项。

(八)测试320(hide)、321(hide_user_process)系统调用

查看本机seu uid=500

每次su进程的pid不一定相同,测试时需要先ps查看su的pid

   

 五、测试

切换内核版本为linux-2.6.21,查看/proc文件夹下生成hidden、hidden_flag两个文件

默认设置hidden_flag=1,允许隐藏进程

  • 测试hide_user_process

测试前top查看当前进程

运行测试文件,


在root用户下,成功隐藏了用户名为seu的进程。

  • 测试hide su进程


ps查看su的pid为4054


运行系统调用,隐藏了pid=4054的进程

将系统调用第三个参数设置为0,su进程又显示出来。

cat查看hidden_process的内容

  • 测试hidden_flag

echo
设置hidden_flag=0,禁止隐藏进程。

本次su进程pid为4520 可以看到su进程没没有被隐藏。


  • 测试用户权限

Seu权限下,pid=4776的bash进程并没有被隐藏,只有root权限可以隐藏进程。

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值