实验环境
Ubuntu 14.04.5 LTS
Linux - 4.15.6
为单个文件进程补丁操作
-
在桌面
Desktop
建立文件夹patch
,作为实验用,然后进入patch
文件夹。建立测试文件test0
、test1
。我们的目标:给
test0
打补丁test1.patch
,使test0
与test1
内容一致:注:使用
diff
创建补丁test1.patch
;源文件test0
;目标文件test1
;因为单个文件,所以不需要-r
选项。选项顺序没有关系,即可以是-uN
,也可以是-Nu
。 -
给源文件
test0
打补丁与恢复:注:
-pN
与patch
文件中列出的文件名有关,N
表示拿掉几个斜线(目录层级);-E
选项说明如果发现了空文件,那么就删除它;-R
选项说明在补丁文件中的“新”文件和“旧”文件现在要调换过来了(实际上就是给新版本打补丁,让它变成老版本)。
为多个文件进行补丁操作
-
在上文中的
/Desktop/patch
文件夹下创建测试文件夹prj0
:注:在
patch
文件夹下,创建文件夹prj0
,并把test0
拷入,再在文件夹prj0
下创建文件prj0name
;创建文件夹prj1
,并把test1
拷入,再在文件夹prj1
下创建文件prj1name
。然后返回patch
目录下。 -
创建补丁
diff
的功能就是用来比较两个文件的不同,然后记录下来,也就是所谓的diff
补丁。语法格式:diff
【选项】 源文件(夹) 目的文件(夹)就是要给源文件(夹)打个补丁,使之变成目的文件(夹),术语也就是“升级”。下面介绍三个最为常用选项:
-r
是一个递归选项,设置了这个选项,diff
会将两个不同版本源代码目录中的所有对应文件全部都进行一次比较,包括子目录文件。-N
选项确保补丁文件将正确地处理已经创建或删除文件的情况。-u
选项以统一格式创建补丁文件,这种格式比缺省格式更紧凑些。注:把所有
prj1
目录下的文件,打补丁到prj0
目录下。注:复制 prj1.patch 到 prj0 文件夹下;
进入 prj0 目录下,打补丁,
-p1
表示prj0/test0
。
下面变通一下,不复制
.patch
文件,执行:总结:
-
单个文件
diff -uN from_file to_file > to_file.patch
patch -p0 < to_file.patch
patch -RE -p0 < to_file.patch
-
多个文件
diff -uNr from_docu to_docu > to_docu.patch
patch -p1 < to_docu.patch
patch -R -p1 < to_docu.patch
-
创建显示系统进程信息的 proc 模块
-
将
tasklist.c
与修改后的tasklist.c
(我们下边命名为:tasklist1.c
) 生成补丁-
首先看一下系统中
proc
目录下是否有tasklist
这个文件 -
创建
tasklist.c
、tasklist1.c
和Makefile
文件:tasklist.c
代码://------------------------------------------------------------------- // tasklist.c: 本内核文件创建一个proc伪文件,'/proc/tasklist' // 通过如下命令可以显示系统中所有进程的部分信息 // 注意:Makefile文件必须正确放置在当前目录下。 // 编译命令: make // 内核模块添加:$sudo insmod tasklist.ko // 添加内核模块后读取并信息tasklist内核信息: $ cat /proc/tasklist // 内核模块删除:$sudo rmmod tasklist // NOTE: Written and tested with Linux kernel version 4.15.6 // strace函数可用于追踪系统调用,命令格式如下所示: // $ strace cat /proc/tasklist //------------------------------------------------------------------- #include <linux/module.h> // for init_module() #include <linux/proc_fs.h> // for create_proc_info_entry() #include <linux/sched/task.h> // for init_task #include <linux/seq_file.h> // for sequence files #include <linux/slab.h> // for kzalloc, kfree #include <linux/sched/signal.h> //for next_task char modname[] = "tasklist"; struct task_struct *task; int taskcounts=0; // 'global' so value will be retained static void * my_seq_start(struct seq_file *m, loff_t *pos) { ///printk(KERN_INFO"Invoke start\n"); //可以输出调试信息 if ( *pos == 0 ) // 表示遍历开始 { task = &init_task; //遍历开始的记录地址 return &task; //返回一个非零值表示开始遍历 } else //遍历过程中 { if (task == &init_task ) //重新回到初始地址,退出 return NULL; return (void*)pos ;//否则返回一个非零值 } } static int my_seq_show(struct seq_file *m, void *v) {//获取进程的相关信息 //printk(KERN_INFO"Invoke show\n"); //输出进程序号 seq_printf( m, "#%-3d\t ", taskcounts++ ); //输出进程pid? //输出进程state? //输出进程名称(comm)? seq_puts( m, "\n" ); return 0; } static void * my_seq_next(struct seq_file *m, void *v, loff_t *pos) { //printk(KERN_INFO"Invoke next\n"); (*pos)++; //task指向下一个进程? return NULL; } static void my_seq_stop(struct seq_file *m, void *v) { //printk(KERN_INFO"Invoke stop\n"); // do nothing } static struct seq_operations my_seq_fops = {//序列文件记录操作函数集合 .start = my_seq_start, .next = my_seq_next, .stop = my_seq_stop, .show = my_seq_show }; static int my_open(struct inode *inode, struct file *file) { return seq_open(file, &my_seq_fops); //打开序列文件并关联my_seq_fops } static const struct file_operations my_proc = { //proc文件操作函数集合 .owner = THIS_MODULE, .open = my_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release }; int __init my_init( void ) { struct proc_dir_entry* my_proc_entry; printk( "<1>\nInstalling \'%s\' module\n", modname ); my_proc_entry = proc_create(modname, 0x644, NULL, &my_proc);//生成proc文件 if (NULL == my_proc_entry) { return -ENOMEM; } return 0; //SUCCESS } void __exit my_exit( void ) { remove_proc_entry( modname, NULL );//删除proc文件 printk( "<1>Removing \'%s\' module\n", modname ); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL");
tasklist1.c
代码://------------------------------------------------------------------- // tasklist.c: 本内核文件创建一个proc伪文件,'/proc/tasklist' // 通过如下命令可以显示系统中所有进程的部分信息 // 注意:Makefile文件必须正确放置在当前目录下。 // 编译命令: make // 内核模块添加:$sudo insmod tasklist.ko // 添加内核模块后读取并信息tasklist内核信息: $ cat /proc/tasklist // 内核模块删除:$sudo rmmod tasklist // NOTE: Written and tested with Linux kernel version 4.15.6 // strace函数可用于追踪系统调用,命令格式如下所示: // $ strace cat /proc/tasklist //------------------------------------------------------------------- #include <linux/module.h> // for init_module() #include <linux/proc_fs.h> // for create_proc_info_entry() #include <linux/sched/task.h> // for init_task #include <linux/seq_file.h> // for sequence files #include <linux/slab.h> // for kzalloc, kfree #include <linux/sched/signal.h> //for next_task char modname[] = "tasklist"; struct task_struct *task; int taskcounts=0; // 'global' so value will be retained static void * my_seq_start(struct seq_file *m, loff_t *pos) { ///printk(KERN_INFO"Invoke start\n"); //可以输出调试信息 if ( *pos == 0 ) // 表示遍历开始 { task = &init_task; //遍历开始的记录地址 return &task; //返回一个非零值表示开始遍历 } else //遍历过程中 { if (task == &init_task ) //重新回到初始地址,退出 return NULL; return (void*)pos ;//否则返回一个非零值 } } static int my_seq_show(struct seq_file *m, void *v) {//获取进程的相关信息 //printk(KERN_INFO"Invoke show\n"); //输出进程序号 seq_printf( m, "#%-3d\t ", taskcounts++ ); //输出进程pid? seq_printf( m, "%5d\t", task->pid ); //输出进程state? seq_printf( m, "%lu\t", task->state ); //输出进程名称(comm)? seq_printf( m, "%-15s ", task->comm ); seq_puts( m, "\n" ); return 0; } static void * my_seq_next(struct seq_file *m, void *v, loff_t *pos) { //printk(KERN_INFO"Invoke next\n"); (*pos)++; //task指向下一个进程? task = next_task(task); return NULL; } static void my_seq_stop(struct seq_file *m, void *v) { //printk(KERN_INFO"Invoke stop\n"); // do nothing } static struct seq_operations my_seq_fops = {//序列文件记录操作函数集合 .start = my_seq_start, .next = my_seq_next, .stop = my_seq_stop, .show = my_seq_show }; static int my_open(struct inode *inode, struct file *file) { return seq_open(file, &my_seq_fops); //打开序列文件并关联my_seq_fops } static const struct file_operations my_proc = { //proc文件操作函数集合 .owner = THIS_MODULE, .open = my_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release }; int __init my_init( void ) { struct proc_dir_entry* my_proc_entry; printk( "<1>\nInstalling \'%s\' module\n", modname ); my_proc_entry = proc_create(modname, 0x644, NULL, &my_proc);//生成proc文件 if (NULL == my_proc_entry) { return -ENOMEM; } return 0; //SUCCESS } void __exit my_exit( void ) { remove_proc_entry( modname, NULL );//删除proc文件 printk( "<1>Removing \'%s\' module\n", modname ); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL");
Makefile
代码:ifneq ($(KERNELRELEASE),) obj-m := tasklist.o else KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules rm -r -f .tmp_versions *.mod.c .*.cmd *.o *.symvers endif
-
给
tasklist.c
打补丁tasklist1.patch
: -
在
~/Desktop/module_test
文件夹下,编译: -
模块
tasklist.ko
已经添加入内核,现在可以查看tasklist
文件的内核信息了:
-
-
通过模块传参,传入进程名隐藏相应进程。
-
卸载模块
tasklist.ko
: -
在
~/Desktop/module_test
目录下,新建如下tasklist2.c
目标文件://------------------------------------------------------------------- // tasklist.c: 本内核文件创建一个proc伪文件,'/proc/tasklist' // 通过如下命令可以显示系统中所有进程的部分信息 // 注意:Makefile文件必须正确放置在当前目录下。 // 编译命令: make // 内核模块添加:$sudo insmod tasklist.ko // 添加内核模块后读取并信息tasklist内核信息: $ cat /proc/tasklist // 内核模块删除:$sudo rmmod tasklist // NOTE: Written and tested with Linux kernel version 4.15.6 // strace函数可用于追踪系统调用,命令格式如下所示: // $ strace cat /proc/tasklist //------------------------------------------------------------------- #include <linux/module.h> // for init_module() #include <linux/proc_fs.h> // for create_proc_info_entry() #include <linux/sched/task.h> // for init_task #include <linux/seq_file.h> // for sequence files #include <linux/slab.h> // for kzalloc, kfree #include <linux/sched/signal.h> //for next_task #include <linux/string.h> char modname[] = "tasklist"; struct task_struct *task; int taskcounts=0; // 'global' so value will be retained static char* var; module_param(var,charp,0644); static void * my_seq_start(struct seq_file *m, loff_t *pos) { ///printk(KERN_INFO"Invoke start\n"); //可以输出调试信息 if ( *pos == 0 ) // 表示遍历开始 { task = &init_task; //遍历开始的记录地址 return &task; //返回一个非零值表示开始遍历 } else //遍历过程中 { if (task == &init_task ) //重新回到初始地址,退出 return NULL; return (void*)pos ;//否则返回一个非零值 } } static int my_seq_show(struct seq_file *m, void *v) {//获取进程的相关信息 //printk(KERN_INFO"Invoke show\n"); //输出进程序号 seq_printf( m, "#%-3d\t ", taskcounts++ ); //输出进程pid? seq_printf( m, "%5d\t", task->pid ); //输出进程state? seq_printf( m, "%lu\t", task->state ); //输出进程名称(comm)? seq_printf( m, "%-15s ", task->comm ); seq_puts( m, "\n" ); return 0; } static void * my_seq_next(struct seq_file *m, void *v, loff_t *pos) { //printk(KERN_INFO"Invoke next\n"); (*pos)++; //task指向下一个进程? task = next_task(task); if(!strcmp(task->comm,var)) { task = next_task(task); } return NULL; } static void my_seq_stop(struct seq_file *m, void *v) { //printk(KERN_INFO"Invoke stop\n"); // do nothing } static struct seq_operations my_seq_fops = {//序列文件记录操作函数集合 .start = my_seq_start, .next = my_seq_next, .stop = my_seq_stop, .show = my_seq_show }; static int my_open(struct inode *inode, struct file *file) { return seq_open(file, &my_seq_fops); //打开序列文件并关联my_seq_fops } static const struct file_operations my_proc = { //proc文件操作函数集合 .owner = THIS_MODULE, .open = my_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release }; int __init my_init( void ) { struct proc_dir_entry* my_proc_entry; printk( "<1>\nInstalling \'%s\' module\n", modname ); printk( KERN_INFO"var=%s\n", var ); my_proc_entry = proc_create(modname, 0x644, NULL, &my_proc);//生成proc文件 if (NULL == my_proc_entry) { return -ENOMEM; } return 0; //SUCCESS } void __exit my_exit( void ) { remove_proc_entry( modname, NULL );//删除proc文件 printk( "<1>Removing \'%s\' module\n", modname ); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL");
给
tasklist.c
打补丁tasklist2.patch
-
在
~/Desktop/module_test
文件夹下:$ make $ sudo insmod tasklist.ko var = "init" $ cat /proc/tasklist
注:
init
进程就被隐藏了。注意:
insmod
命令后一定要给var
传递参数,否则可能会出现下面问题解决办法是重启系统,重新加在模块(执行
insmod
命令)并记得给var
传递参数。 -
卸载
tasklist.ko
模块,重新insmod
进内核,var
赋个空字符串。init
进程就显示了: -
上述办法是在执行
insmod
命令时,给变量var
(进程名)赋值。归根结底是tasklist.c
文件中变量var
未初始化造成的,另一种办法是初始化tasklist.c
文件中的变量var
。比如:static char* var; // 将此行替换为下面这行 static char* var = " "; // 给 var 初始化为空串
然后:
$ make $ sudo insmod tasklist.ko // 此处可不给var传参,因为代码中已经初始化了 $ cat /proc/tasklist // 显示全部进程 $ sudo rmmod tasklist.ko // 卸载tasklist.ko模块 $ sudo insmod tasklist.ko var = "输入你想隐藏的进程名" $ cat /proc/tasklist // 发现指定的进程已被隐藏,显示隐藏的进程请看前一步
-