内核模块编写从入门到放弃

简介

我是第一次接到写内核模块的作业,基本是从零开始。该文章适合什么都不会的小白围观,有错误希望指正。
以我做的ip包加密任务为例,学习内核模块的编写。使用的环境是Ubuntu和c语言环境。内核模块的编写和内核版本息息相关,不同的版本的内核函数名和数据结构名都不同,由于网上的教程一般比较老,因此在初学的时候,建议使用内核版本在4.10一下的系统。
内核版本查看方式是uname -r。
另需要强调的是,测试记得用虚拟机,不然分分钟搞崩您的系统。

基本结构

头文件

内核程序一般有很多头文件,例如:
#include <linux/kernel.h>
#include <linux/module.h>
这些头文件能在/usr/include/linux文件夹和/usr/scr/内核版本/include/linux里找到,其中/usr/scr/内核版本/include/linux是完整的版本。当然在刚刚编写的时候不需要了解,但在出现如找不到头文件等bug时可能有一点帮助。
插一句:一般头文件找不到都是编译方法的错误。

Module

除了头文件、全局变量和函数的定义外,内核程序都包含一下内容:
module_init(initmodule);
module_exit(cleanupmodule);
MODULE_LICENSE(“GPL”);

分别表示初始化模块,清除模块和license。在插入模块时,执行initmodule,在模块被清除时,执行cleanupmodule。内核模块与一般的c程序不同,并不是把需要做的事以结构化的方式写在main函数中。以我的ip包加密为例,我只需要在初始化模型时,注册一个hook函数,当一个 ip包通过检查点是,会激活这个函数并执行我编写的加密操作。

init和exit函数

static int __init initmodule(void)
初始化模块函数是必要的用来初始化模块的,可以实现的操作有如注册hook函数、注册设备节点文件等。
static void __exit cleanupmodule(void)
在清除模块时被调用,执行的操作有注销hook函数、注销设备节点文件等操作。
至此,这就是内核程序的必要结构啦。

编译

首先要强调,内核程序的编译不是用gcc的!!(天真可爱的我一开始就是这么编译的)
编译内核文件一般在同目录下放一个makefile文件,内容是:
obj-m += 内核程序文件名.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C ( K D I R ) M = (KDIR) M= (KDIR)M=(PWD) modules

然后!在终端运行make就完成编译啦!
在default部分后,还可以接其它需要编译的辅助文件,如接
gcc xxx.c -o xxx.o

运行

编译完会生成一堆如.ko,.mod.c等文件,具体我们不用了解,我们只要知道怎么运行就好了!在终端输入:
sudo insmod 内核程序文件名.ko
就完成插入内核了!此时执行的是刚刚提到的initmodule函数。
当需要清除这个模块时输入:
sudo rmmod 内核程序文件名.ko
就实现了关闭内核,此时执行cleanupmodule函数。

输出

内核程序的打印使用的函数是printk(),打印在日志上,查看方式是$dmesg。

参数设置

如果需要设置一些程序中有用的参数,一般需要通过文件传输。
首先,写一个普通c程序(非内核)进行命令行参数的输入和提取,并写入设备文件/dev/info
其次,在内核程序中注册该设备结点文件,在initmodule中添加:
register_chrdev(124, “/dev/info”, &fops)
fops是需要自己定义的文件操作结构,其中包含结构,有操作函数和owner,操作函数在文件中读取参数并赋给程序中的变量。

有关我的程序

我写的是hook,使用的是netfilter完成ip包正文内容的加密,涉及的数据结构有skb。

hook

定义结构体为nf_hook_ops。
在initmodule中注册和挂载,可以挂载多个函数。需要赋值的内容有
.hook:自己写的挂载执行的函数名
.hooknum:挂载点
.priority:优先级
.pf:PF_INET
最后使用nf_register_hook(&myhook)完成注册

skb结构

skb结构是ip包传输的结构。
Skb:TCP/IP堆栈中用于收发包的缓冲区域。具体有:Skb->data:数据区起始位置,即IP数据包起始位置。Skb->len:数据区总长度。
skb_network_header(skb):获取IP数据包起始位置。输入为skb结构。
ip_hdr(skb):数据结构,可获取IP头的信息。输入为skb。具体有:ip_hdr(skb)->ihl:该数据*4为IP头长度,可计算出正文开始位置。ip_hdr(skb)->daddr:目的地址。ip_hdr(skb)->protocol:协议类型。ip_hdr(skb)->tot_len:ip包长度,需要大小端转换。
tcp_hdr(skb):数据结构,可获取IP头的信息。tcp_hdr(skb)->doff:*4为报头长度。

写在最后

内核程序可以说耗尽了我所有的耐心,搞崩了我无数的虚拟机,经历了这怎么会跑不通和这怎么可能跑通两大必经点。
总之,完成作业还是成就感满满,希望诸君顺利,写内核还是需要good luck啦~~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值