• 转 32位linux内核2.6.38.2添加系统调用,编写类似"ps"命令模块显示进程信息


     

    现在我用的是虚拟机下ubuntu10.10,内核版本已经升级到2.6.38.2,要完成的任务有: 

    TASK 1:在内核的结构体task_struct中添加一个数据成员ctx,记录每个进程切换(被调度)的次数,并编写一个模块显示进程的信息,包括该数据成员的值;

    TASK 2:在内核中增加一个系统调用,并编写用户态程序调用该系统调用; 

    首先修改内核源码(最好是之前make的源码)

    FIRST:基于TASK 1的源码修改

    1. 在task_struct中添加一个数据成员,在源码文件include/linux/sched.h中找到task_struct所在位置,添加一个成员ctx记录每个进程切换(被调度)的次数。如下图:

    2.在源码文件kernel/fork.c中找到do_fork函数,在其中初始化该数据成员ctx,初始化的位置是进程刚被建立的地方,而linux系统建立进程一般都是通过复制父进程的数据结构来完成的,所以在cope_process被执行后,添加初始化,代码添加如下图:

    3. 在源码文件kernel/sched.c中找到schedule函数,当进程(switch)发生切换时,即被调度时需要对ctx加一,代码添加如下图:

    SECOND:基于TASK 2的源码修改

    1. 在源码文件kernel/sys.c文件代码的末尾处加入自定义的系统调用函数sys_mysyscall ,代码如下图:

    2. 在源码文件arch/x86/include/asm/unistd_32.h中添加一个系统调用号的定义 “#define __NR_mysyscall  341”,并把最后的那个“__NR_syscall 341”改为“__NR_syscall 342“,这相当于一个结束符,标志系统调用的总数,我们的系统调用号要加在该结束符前面,其最终代码如下图:

    3. 在源码文件arch/x86/kernel/syscall_table_32.S中为自己的系统调用添加指针引用,这对数据的录入和你分配给自己系统调用的索引保持一致很重要,其代码添加在最后一行:

    .long sys_mysyscall

    以上的修改可参考之后的patch文件;

    THIRD:编译内核

    1. make mrproper:清除之前编译内核时的残存配置文件,和一些生成的映像。

    2. 重新编译内核,请参考前一篇文章《跟党哥学linux内核系列之(ubuntu10.10下编译linux内核,升级内核到2.6.38.2)》,但注意,无须编译modules,只需执行命令make bzImage -j4,时间在30分钟左右,然后reboot就ok了。

    FORTH:c文件代码

    1. TASK 1中类似于“ps”命令的模块proc.c

    1.1 相关数据结构:

    struct file结构,该结构是字符设备驱动的重要结构,文件结构代表一个打开的文件描述符,它不是专门给驱动程序使用的,系 统中每一个打开的文件在内核中都有一个关联的struct file。它由内核在open时创建,并传递给在文件上操作的任何函数,知道最后关闭。当文件的所有实例都关闭之后,内核释放这个数据结构。

    struct seq_file结构,该结构会在seq_open函数调用中分配,然后作为参数传递给每个seq_file的操作函数。Private变量可以用来在各个操作函数之间传递参数。

    struct inode结构,每个存储设备或存储设备的分区被格式化为文件系统后,应该有两部份,一部份是inode,另一部份是Block,Block是用来存储数据用的。而inode就是用来存储这些数据的信息,这些信息包括文件大小、属主、归属的用户组、读写权限等。inode为每个文件进行信息索引,所以就有了inode的数值。操作系统根据指令, 能通过inode值最快的找到相对应的文件。当我们用ls查看某个目录或文件时,如果加上-i参数,就可以看到inode节点了,比如ls -li lsfile.sh,最前面的数值就是inode信息。

    1.2 proc.c代码如下:

    /** 
    *@author DangYan 
    *It's a test module like 'ps' 
    **/


    #include <linux/init.h> 
    #include <linux/module.h> 
    #include <linux/proc_fs.h> //proc_fs 
    #include <linux/seq_file.h> //seq_file 
    #include <linux/fs.h> //struct file,struct inode 
    #include <linux/sched.h>    //next_task() 

    MODULE_AUTHOR("DangYan_1001220893"); 
    MODULE_LICENSE("GPL"); 
    MODULE_DESCRIPTION("a test module like 'ps'"); 

    static void *ps_seq_start(struct seq_file *s,loff_t *pos){ 
    struct task_struct *task; 

    seq_printf(s,"%s %s %s ","pid","ctx","comm"); //读取格式 

    if(*pos>0) 
    return NULL; 
    else{ 
    task=next_task(current); 
    return task; 



    static void *ps_seq_next(struct seq_file *s,void *v,loff_t *pos){ 
    struct task_struct *task=(struct task_struct *)v; 
    ++*pos; 
    if(task->pid== current->pid){ 
    return NULL; 
    }else{ 
    task=next_task(task); 
    return task; 



    static void ps_seq_stop(struct seq_file *s,void *v){} 

    static int ps_seq_show(struct seq_file *s,void *v){ 
    rwlock_t lock = RW_LOCK_UNLOCKED; 
    struct task_struct *task=(struct task_struct *)v; 
    read_lock(&lock); 

    seq_printf(s,"%d %d %s ",task->pid,task->ctx,task->comm); 

    read_unlock(&lock); 
    return 0; 


    static struct seq_operations ps_seq_ops = { 
    .start = ps_seq_start, 
    .next = ps_seq_next, 
    .stop = ps_seq_stop, 
    .show = ps_seq_show 
    }; 

    static int ps_open(struct inode *inode,struct file *file){ 
    return seq_open(file,&ps_seq_ops); 


    static struct file_operations ps_file_ops = { 
    .owner = THIS_MODULE, 
    .open = ps_open, 
    .read  =  seq_read, 
    .llseek = seq_lseek, 
    .release= seq_release 
    }; 



    static int __init ps_init(void){ 
    struct proc_dir_entry *entry; 
    entry = create_proc_entry("plist",0,NULL); 
    if(entry) 
    entry->proc_fops = &ps_file_ops; 
    return 0; 


    static void __exit ps_exit(void){ 
    remove_proc_entry("plist",NULL); 


    module_init(ps_init); 
    module_exit(ps_exit);

    1.3 makefile文件,代码如下:

    obj-m += proc.o 
    default: 
        $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 
    clean: 
        $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

    1.4 加载模块proc.ko

    首先在proc.c的根目录下执行make命令进行编译

    然后执行sudo insmod proc.ko来加载module

    查看当前已加载模块信息:lsmod

    卸载模块sudo rmmod pro_example

    当加载完模块后,就可以查看/proc目录下是否生成了相应的文件,并使用cat命令查看文件内容,还可以使用dmesg查看后台打印信息,比如printk的输出,如果要看的更清除一点,使用sudo dmesg -c清除之前的信息

    2. TASK 2使用syscall函数编写用户态程序

    代码如下:

    #include <linux/unistd.h>  
    #include <stdio.h>  

    int main()  
    {  
       printf("My syscall number =%d ", syscall(341,1));  
       return 0;  
    }

    运行程序,输出结果为1,查看dmesg,有success;则系统调用添加成功,调用该系统调用正确。

    FIFTH:前后内核文件的patch

    diff -ruNa linux-2.6.38.2/arch/x86/include/asm/unistd_32.h linux-2.6.38.2org/arch/x86/include/asm/unistd_32.h 
    --- linux-2.6.38.2/arch/x86/include/asm/unistd_32.h    2011-04-14 17:53:41.849076001 +0800 
    +++ linux-2.6.38.2org/arch/x86/include/asm/unistd_32.h    2011-03-28 02:37:20.000000000 +0800 
    @@ -346,11 +346,10 @@ 
     #define __NR_fanotify_init    338 
     #define __NR_fanotify_mark    339 
     #define __NR_prlimit64        340 
    -#define __NR_mysyscall          341   /* dangyan */ 
     
     #ifdef __KERNEL__ 
     
    -#define NR_syscalls 342 
    +#define NR_syscalls 341 
     
     #define __ARCH_WANT_IPC_PARSE_VERSION 
     #define __ARCH_WANT_OLD_READDIR 
    diff -ruNa linux-2.6.38.2/arch/x86/kernel/syscall_table_32.S linux-2.6.38.2org/arch/x86/kernel/syscall_table_32.S 
    --- linux-2.6.38.2/arch/x86/kernel/syscall_table_32.S    2011-04-14 17:53:40.689076002 +0800 
    +++ linux-2.6.38.2org/arch/x86/kernel/syscall_table_32.S    2011-03-28 02:37:20.000000000 +0800 
    @@ -340,4 +340,3 @@ 
         .long sys_fanotify_init 
         .long sys_fanotify_mark 
         .long sys_prlimit64        /* 340 */ 
    -        .long sys_mysyscall             /* 341 dangyan */ 
    diff -ruNa linux-2.6.38.2/include/linux/sched.h linux-2.6.38.2org/include/linux/sched.h 
    --- linux-2.6.38.2/include/linux/sched.h    2011-04-14 17:54:19.457076000 +0800 
    +++ linux-2.6.38.2org/include/linux/sched.h    2011-03-28 02:37:20.000000000 +0800 
    @@ -1191,7 +1191,6 @@ 
     }; 
     
     struct task_struct { 
    -        unsigned int ctx;       /* dangyan */ 
         volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */ 
         void *stack; 
         atomic_t usage; 
    diff -ruNa linux-2.6.38.2/kernel/fork.c linux-2.6.38.2org/kernel/fork.c 
    --- linux-2.6.38.2/kernel/fork.c    2011-04-14 17:52:17.245075996 +0800 
    +++ linux-2.6.38.2org/kernel/fork.c    2011-03-28 02:37:20.000000000 +0800 
    @@ -1437,8 +1437,6 @@ 
         if (!IS_ERR(p)) { 
             struct completion vfork; 
     
    -                p->ctx = 0;          /* dangyan */ 
    - 
             trace_sched_process_fork(current, p); 
     
             nr = task_pid_vnr(p); 
    diff -ruNa linux-2.6.38.2/kernel/sched.c linux-2.6.38.2org/kernel/sched.c 
    --- linux-2.6.38.2/kernel/sched.c    2011-04-14 17:52:18.061076002 +0800 
    +++ linux-2.6.38.2org/kernel/sched.c    2011-03-28 02:37:20.000000000 +0800 
    @@ -3995,7 +3995,6 @@ 
             rq->nr_switches++; 
             rq->curr = next; 
             ++*switch_count; 
    -                next->ctx++;               /* dangyan */ 
     
             context_switch(rq, prev, next); /* unlocks the rq */ 
             /* 
    diff -ruNa linux-2.6.38.2/kernel/sys.c linux-2.6.38.2org/kernel/sys.c 
    --- linux-2.6.38.2/kernel/sys.c    2011-04-14 17:52:18.221075999 +0800 
    +++ linux-2.6.38.2org/kernel/sys.c    2011-03-28 02:37:20.000000000 +0800 
    @@ -1763,19 +1763,6 @@ 
     } 
     
     /** 
    -*@author:dangyan 
    -*sys_mysyscall 
    -*This is an testing system call 
    -*/ 
    - asmlinkage int sys_mysyscall(int mysyscall_num) 
    -{ 
    -        printk(KERN_INFO "success! "); 
    - 
    -        return mysyscall_num; 
    -   
    -} 
    - 
    -/** 
      * orderly_poweroff - Trigger an orderly system poweroff 
      * @force: force poweroff if command execution fails 

  • 相关阅读:
    【原创】使用开源libimobiledevice盗取iphone信息
    【原创】Arduino制作Badusb实践
    【原创】Aduino小车玩法全记录
    【原创】Arduino入门基础知识总结
    【原创】Arduino、arm、树莓派与单片机
    【原创】PM3破解IC卡记录
    【转】反编译D-Link路由器固件程序并发现后门
    DDOS分布式拒绝服务
    XSS 初识
    针对企业级别渗透测试流程
  • 原文地址:https://www.cnblogs.com/i0ject/p/3658026.html
Copyright © 2020-2023  润新知