Linux实践二:模块
一、基本模块的实现:
1.进程遍历打印输出
2.简单地编写一个新的系统调用(替换空的系统调用号)
基本模块学到的知识点:
1.相关指令
make oldconfig 配置内核
make 编译内核
make modules_instal 编译安装内核模块
make install 引导新编译的内核
uname –a 查看内核版本
lsmod 查看加载的模块
insmod 加载模块
rmmod 卸载模块
dmesg 显示开机信息
基础模块一:系统调用(替换空的233)
文件Makefile
obj-m :=syscall.o
PWD := $(shell pwd)
KDIR:=/lib/modules/4.4.0-21-generic/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
uname -r 显示当前使用的内核信息,确定自己当前linux的内核版本是多少
测试代码:
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned long x = 0;
x = syscall(223); //测试223号系统调用
printf("Hello, %ld\n", x);
return 0;
}

make -C $(LINUX_KERNEL_PATH) 指明跳转到内核源码目录下读取那里的Makefile
M=$(CURRENT_PATH) 表明返回到当前目录继续执行当前的Makefile。
头文件module.h,必须包含此文件;
头文件kernel.h,包含常用的内核函数;
头文件init.h包含宏_init和_exit,允许释放内核占用的内存。
基础模块二:进程遍历

二、深入
学习一:页表模块
基本思路:
1.研究学习学姐的实践指导书,由于新版本的Ubuntu需要的是四级页表,根据百度的一些知识,将学姐的代码由二级页表修改成四级页表
(重点是理解页表结构)
2.进一步修改页表,修改权限,使得用户态的可以变成内核态(研究中)。
对于页的保护通常设置一个存取控制字段。当这个字段占一位时,用于规定该页中的内 容允许写还是读;如果存取控制字段占两位,那么它可以表示存取控制为读写、只读和 只运行三种。当进程写一个只读页时,系统就会通过中断来报错。
模块参数以module_param(name,type,perm)的形式定义,其中name为参数名,type为参数的数据类型,perm是一个权限值,控制谁可以存取模块参数在sysfs中的表示。
页全局目录(Page Global Directory)
• 页上级目录(Page Upper Directory)
• 页中间目录(Page Middle Directory)
• 页表(Page Table)
页全局目录包含若干页上级目录的地址,页上级目录又依次包含若干页中间目录的地址,而页中间目录又包含若干页表的地址。每一个页表项指向一个页框。线性地址因此被分成五个部分。图中没有显示位数,因为每一部分的大小与具体的计算机体系结构有关。
#include <linux/module.h>
#include <asm/pgtable.h>
#include <linux/version.h>
#include <asm/page.h>
#include <linux/gfp.h>
#include <linux/page-flags.h>
#include <linux/sched.h>//find_task_by_vpid
#include <linux/mm.h>//find_vma MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CONVERT USER VIRTUAL ADDRESS TO PHYADDRESS"); static int pid;
static unsigned long va; module_param(pid,int,0644);
module_param(va,ulong,0644); static int find_pgd_init(void)
{
unsigned long pa=0;
struct task_struct *pcb_tmp=NULL;
pgd_t *pgd_tmp=NULL;
pud_t *pud_tmp=NULL;
pmd_t *pmd_tmp=NULL;
pte_t *pte_tmp=NULL; printk(KERN_ALERT "test:va=0x%lx,pid=%d.\n",va,pid); rcu_read_lock();
if( !( pcb_tmp = pid_task(find_vpid(pid), PIDTYPE_PID) ) )
{
rcu_read_unlock();
printk(KERN_ALERT "Can't find the task %d.\n",pid);
return 0;
}
rcu_read_unlock(); printk("The page index_table address = 0x%p\n\n",pcb_tmp->mm->pgd); printk(KERN_ALERT "pgd=0x%p\n",pcb_tmp->mm->pgd);
if(!find_vma(pcb_tmp->mm,va))
{
printk(KERN_ALERT "virt_addr 0x%lx not available.\n",va);
return 0;
}
pgd_tmp=pgd_offset(pcb_tmp->mm,va);
printk(KERN_ALERT "pgd_tmp=0x%p\n",pgd_tmp);
printk(KERN_ALERT "pgd_val(*pgd_tmp)=0x%lx\n\n",pgd_val(*pgd_tmp));
if(pgd_none(*pgd_tmp))
{
printk(KERN_ALERT "Not mapped in pgd.\n");
return 0;
} pud_tmp=pud_offset(pgd_tmp,va);
pmd_tmp=pmd_offset(pud_tmp,va); pte_tmp=pte_offset_kernel(pmd_tmp,va);
if(pte_none(*pte_tmp))
{
printk(KERN_ALERT "Not mapped in pte.\n");
return 0;
}
if(!pte_present(*pte_tmp))
{
printk(KERN_ALERT "pte not in RAM,maybe swaped.\n");
return 0;
}
pa=(pte_val(*pte_tmp)&PAGE_MASK)|(va&~PAGE_MASK);
printk(KERN_ALERT "Virtual address: 0x%lx in RAM is 0x%lx.\n",va,pa);
printk(KERN_ALERT "Part content in 0x%lx is 0x%lx.\n",pa,*(unsigned long*)((char *)pa+PAGE_OFFSET));
int i;
printk("some content:\n");
for(i=0;i<40;i=i+4)
{
printk("%lx\n",*(unsigned long*)((char*)pa+PAGE_OFFSET+i));
}
return 0;
} static void find_pgd_exit(void)
{
printk(KERN_ALERT "Goodbye.\n");
} module_init(find_pgd_init);
module_exit(find_pgd_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("weiwei"); MODULE_DESCRIPTION("GET WESSAGE");

- 页全局目录(Page Global Directory)
- 页上级目录(Page Upper Directory)
- 页中间目录(Page Middle Directory)
- 页表(Page Table)
页全局目录包含若干页上级目录的地址,页上级目录又依次包含若干页中间目录的地址,而页中间目录又包含若干页表的地址。每一个页表项指向一个页框。线性地址因此被分成五个部分。


修改权限的思路,查看页表的读写,u/s的值,然后通过相关的设置函数进行修改
|
函数名称 |
说明 |
|
pte_user( ) |
读 User/Supervisor 标志。 |
|
pte_read( ) |
读 User/Supervisor 标志(表示 80x86 处理器上的页不受读的保护)。 |
|
pte_write( ) |
读 Read/Write 标志。 |
|
pte_exec( ) |
读 User/Supervisor 标志( 80x86 处理器上的页不受代码执行的保护)。 |
|
pte_dirty( ) |
读 Dirty 标志。 |
|
pte_young( ) |
读 Accessed 标志。 |
|
pte_file( ) |
读 Dirty 标志(当 Present 标志被清除而 Dirty 标志被设置时,页属于一个非线性磁盘文件映射)。 |
设置页表项中各标志的值的函数:
|
函数名称 |
说明 |
|
mk_pte_huge( ) |
设置页表项中的 Page Size 和 Present 标志。 |
|
pte_wrprotect( ) |
清除 Read/Write 标志。 |
|
pte_rdprotect( ) |
清除 User/Supervisor 标志。 |
|
pte_exprotect( ) |
清除 User/Supervisor 标志。 |
|
pte_mkwrite( ) |
设置 Read/Write 标志。 |
|
pte_mkread( ) |
设置 User/Supervisor 标志。 |
|
pte_mkexec( ) |
设置 User/Supervisor 标志。 |
|
pte_mkclean( ) |
清除 Dirty 标志。 |
|
pte_mkdirty( ) |
设置 Dirty 标志。 |
|
pte_mkold( ) |
清除 Accessed 标志(把此页标记为未访问)。 |
|
pte_mkyoung( ) |
设置 Accessed 标志(把此页标记为访问过)。 |
|
pte_modify(p,v) |
把页表项 p 的所有访问权限设置为指定的值 v 。 |
|
ptep_set_wrprotect() |
与 pte_wrprotect( ) 类似,但作用于指向页表项的指针。 |
|
ptep_set_access_flags( ) |
如果 Dirty 标志被设置为 1 则将页的访问权设置为指定的值,并调用flush_tlb_page() 函数。 |
|
ptep_mkdirty( ) |
与 pte_mkdirty( ) 类似,但作用于指向页表项的指针。 |
|
ptep_test_and_clear_dirty( ) |
与 pte_mkclean( ) 类似,但作用于指向页表项的指针并返回 Dirty 标志的旧值。 |
|
ptep_test_and_clear_young( ) |
与 pte_mkold( ) 类似,但作用于指向页表项的指针并返回 Accessed标志的旧值。 |
学习二:系统调用
学习三:进程模块
Linux实践二:模块的更多相关文章
- Linux及安全实践二——模块
Linux及安全实践二--模块 一.模块的编译.生成.测试.删除 1.编写模块代码 编写:gedit 3.c 2.编写Makefile obj-m :这个变量是指定你要声称哪些模块模块的格式为 obj ...
- LINUX实践之模块
模块实践 --关于模块代码部分 ---首先是.c代码: 一定会用到的函数有这几个:module_init().module_exit().MODULE_LICENSE() 会用到的头文件:module ...
- 20135337——Linux实践二:模块
一.编译&生成&测试&删除 1.编写模块代码,查看如下 gedit 1.c(编写) cat 1.c(查看) MODULE_AUTHOR("Z") MODUL ...
- 20135218 Linux 实践二 编译模块
20135218 姬梦馨 1.编写模块代码 模块构造函数:执行insmod或modprobe指令加载内核模块时会调用的初始化函数.函数原型必须是module_init(),括号内是函数指针 模块析构函 ...
- Linux实践:模块
标签(空格分隔): 20135321余佳源 一.实践原理 Linux模块是一些可以作为独立程序来编译的函数和数据类型的集合.之所以提供模块机制,是因为Linux本身是一个单内核.单内核由于所有内容都集 ...
- 【实践报告】Linux实践二
3.编译并安装内核与模块 sudo make bzImage –j3 编译内核 sudo make modules –j3 编译模块 sudo make modules ...
- linux内核分析实践二学习笔记
Linux实践二--内核模块的编译 标签(空格分隔): 20135328陈都 理解内核的作用 Linux内核[kernel]是整个操作系统的最底层,它负责整个硬件的驱动,以及提供各种系统所需的核心功能 ...
- Linux课程实践二:编译模块实现内核数据操控
一.内核模块原理 1. Linux内核增加功能 Linux内核整体结构很庞大,包含了很多的组件,现在有两种方法将需要的功能包含进内核当中: - 静态加载:将所有的功能都编译进Linux内核. - 动态 ...
- 《linux内核设计与实现》实践之模块及深入
<linux内核设计与实现>实践之模块及深入 写在前面的话. 基础模块部分我已经做完了,设计到的知识点无非就是,编写模块代码,编写Makefile文件,加载模块和卸载模块部分.由于大家都 ...
随机推荐
- Linux 小知识翻译 - 「Shell」(也就是命令行接口)
这次说说关于Shell的东西. 「Shell」是看不见实体的,所以理解起来可能会有些困难. 最近的Linux发行版默认都是用X Window System来操作的(也就是图形化操作),所以很少见到有人 ...
- elasticsearch版本控制及mapping映射属性介绍
学习elasticsearch不仅只会操作,基本的运行原理我们还是需要进行了解,以下内容我讲对elasticsearch中的基本知识原理进行梳理,希望对大家有所帮助! 一.ES版本控制 1.Elast ...
- jquery的自定义事件通过on绑定trigger触发
jquery绑定自定义事件,可以实现预先绑定好一个处理方法,当需要使用的时候利用jquery trigger来触发自定义事件,以达到方便快捷的目的.我们来假设一个这样的场景,一个textarea中的字 ...
- 控件布局_FrameLayout(网格布局)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&qu ...
- MapReduce全局变量之捉虫记
全局变量 写MapReduce程序时候,有时候须要用到全局变量,经常使用的全局变量实现由三种方式: 通过作业的Configuration传递全局变量.作业初始化的时候.conf.set(),须要的时候 ...
- Java中集合删除元素时候关于ConcurrentModificationException的迷惑点
下面的示例来至于阿里巴巴Java开发手册的集合处理部分的第7条: 运行如下代码,会发现正确运行. public static void hasNotExcption() { List<Strin ...
- day14 Python集合的补充
python_1 = ['charon','pluto','ran','charon'] linux_1 = ['ran','xuexue','ting'] p_s = set(python_1) l ...
- java FTP各种操作
package com.ailk.qw.util; import it.sauronsoftware.ftp4j.*;import org.slf4j.Logger;import org.slf4j. ...
- Linux上VsCode编译打包运行
前提:最好使用root用户可以排除一些不必要的错误. 一. 准备环境 Node.js(>= 8.12.0, < 9.0.0) Python2.7 Yarn(可以通过npm install ...
- WaitForSingleObject的详细用法
在多线程的情况下,有时候我们会希望等待某一线程完成了再继续做其他事情,要实现这个目的,可以使用Windows API函数WaitForSingleObject,或者WaitForMultipleObj ...