2.1 代码示例
在Linux系统下创建一个名为rl_module.c的文件,填入如下内容:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/syscalls.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/netdevice.h>
#include <linux/list.h>
MODULE_LICENSE("Dual BSD/GPL");
static int __init rl_init(void)
{
printk("RL Module init!\n");
return 0;
}
static void __exit rl_exit(void)
{
printk("RL Module exit!\n");
}
module_init(rl_init);
module_exit(rl_exit);
再创建一个Makefile文件,填入如下内容:
#
# Makefile for linux/drivers/platform/x86
# x86 Platform-Specific Drivers
#
MODULE_NAME = rootkit-linux
ifneq ($(KERNELRELEASE),)
obj-m := $(MODULE_NAME).o
$(MODULE_NAME)-objs := rl_module.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
#KERNELDIR ?= /usr/src/linux
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
rm *.o *.ko *.symvers *.order .*.cmd *.markers $(MODULE_NAME).mod.c .tmp_versions -rf
执行make,会得到名为rootkit-linux.ko的文件。
执行insmod命令加载模块:
#insmod rootkit-linux.ko
用dmesg命令查看内核信息,会找到“RLModule init!”。使用sys文件系统或lsmod也会查到rootkit-linux模块的信息:
使用rmmod命令可以卸载模块:
2.2模块加载流程
代码示例中所描述的是实现在Linux下加载模块的通常方法。这时出现几个问题:使用insmod、modprobe命令加载模块时Linux内核都做了哪些工作?模块中用module_init和module_exit注册的函数是如何被调用的?要解答这些问题就需要了解Linux模块加载的流程。
2.2.1module_init函数和module_exit
Linux模块需要用module_init函数注册模块初始化函数,这个函数会在模块加载时由系统调用;用module_exit函数注册模块卸载函数,这个函数会在模块卸载时被调用。
在include/linux/init.h中,module_init和module_exit有两个定义,一个在MODULE宏没有定义时生效,一个MODULE宏被定义时生效。在模块中MODULE宏会被定义,来看看这种情况下的定义:
296 /* Each module must use one module_init(). */
297 #define module_init(initfn) \
298 static inline initcall_t __inittest(void) \
299 { return initfn; } \
300 int init_module(void) __attribute__((alias(#initfn)));
301
302 /* This is only required if you want to be unloadable. */
303 #define module_exit(exitfn) \
304 static inline exitcall_t __exittest(void) \
305 { return exitfn; } \
306 void cleanup_module(void) __attribute__((alias(#exitfn)));
可见module_init和module_exit宏是将它们的入参函数分别重命名为init_module和cleanup_module。
代码编译完毕后生成的rootkit-linux.ko文件的格式是ELF。由于__init的作用,rl_init函数的代码被放在.init.text中,