您的位置:首页 > 运维架构 > Linux

Linux:内核模块实现替换系统调用的简单例子

2017-09-14 09:08 591 查看
原文链接:http://blog.csdn.net/ddk3001/article/details/51485135

编写Linux内核模块,可以实现替换系统调用功能。 

本文提供一个替换open系统调用的样例代码,功能和说明见代码。

参考代码:https://github.com/ricardoteixas/hook 

在 https://github.com 中搜索 hook、kernel等,可以搜到很多可参考的代码。 

/***************************************************************************

文件 : hook_open.c

功能 : 这是一个简单的内核模块,功能是替换了系统调用oepn,实现自定义open功能。

关键函数 :
my_sys_open         // 自定义的open系统调用处理函数
syscall_init        // 内核模块初始化函数
syscall_release     // 内核模块退出函数

源代码参考 :  https://github.com/ricardoteixas/hook 
***************************************************************************/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/syscalls.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/version.h>

/**************************************************************************/
//
/**************************************************************************/

// Write Protect Bit (CR0:16)
#define CR0_WP 0x00010000

MODULE_LICENSE("GPL");

void **syscall_table;

unsigned long **find_sys_call_table(void);

// !!!!!
asmlinkage long  (*orig_sys_open)(const char __user *filename, int flags, umode_t mode);

/***************************************************************************
* /boot/System.map-3.13.0-43-generic:
*
* ffffffff811bb230 T sys_close
* ffffffff81801400 R sys_call_table
* ffffffff81c15020 D loops_per_jiffy
*
**************************************************************************/
unsigned long **find_sys_call_table()
{
unsigned long ptr;
unsigned long *p;

for (ptr = (unsigned long) sys_close; ptr < (unsigned long) &loops_per_jiffy; ptr += sizeof(void *))
{

p = (unsigned long *) ptr;

if (p[__NR_close] == (unsigned long) sys_close)
{
return (unsigned long **) p;
}
}

return NULL;
}

/**************************************************************************/
//
// 自定的open系统调用函数: 如果要打开的是 /home/test1.txt,则改为打开 /home/test2.txt
//
// 关键函数: strncpy_from_user 、 set_fs 、set_fs
//
/**************************************************************************/
asmlinkage long my_sys_open( const char __user  *filename, int flags, umode_t mode )
{
char temp[256] = { 0 };
char *test2 = "/home/test2.txt";

// 需要把用户空间的数据拷贝到内核空间,才能使用
(void)strncpy_from_user( temp, filename, PATH_MAX );

if ( !strcmp( temp, "/home/test1.txt" ) )
{
mm_segment_t fs_save;
long ret;

// get_fs 和 set_fs 是为了使系统调用函数能够访问内核空间数据(本来参数应该是用户空间数据)
// 关于 get_fs 和 set_fs,参考: http://blog.chinaunix.net/uid-27717694-id-4076498.html 
fs_save = get_fs();

set_fs( get_ds() );
ret = orig_sys_open( (const char __user *)test2, flags, mode );
set_fs( fs_save );

return ret;
}

return orig_sys_open(filename, flags, mode);
}

/**************************************************************************/
//
// 内核模块初始化函数
//
/**************************************************************************/
static int __init syscall_init(void)
{
unsigned long cr0;

printk(KERN_DEBUG "Let's do some magic!\n");

syscall_table = (void **) find_sys_call_table();

if (! syscall_table) {
printk(KERN_DEBUG "ERROR: Cannot find the system call table address.\n");
return -1;
}

printk(KERN_DEBUG "Found the sys_call_table at %16lx.\n", (unsigned long) syscall_table);

cr0 = read_cr0();
write_cr0(cr0 & ~CR0_WP);

printk(KERN_DEBUG "Houston! We have full write access to all pages. Proceeding...\n");

orig_sys_open = syscall_table[__NR_open];
syscall_table[__NR_open] = my_sys_open;

write_cr0(cr0);

return 0;
}

/**************************************************************************/
//
// 内核模块退出函数
//
/**************************************************************************/
static void __exit syscall_release(void)
{
unsigned long cr0;

printk(KERN_DEBUG "I hate you!\n");

cr0 = read_cr0();
write_cr0(cr0 & ~CR0_WP);

syscall_table[__NR_open] = orig_sys_open;
//syscall_table[__NR_access] = orig_sys_access;

write_cr0(cr0);
}

/**************************************************************************/
//
/**************************************************************************/
module_init(syscall_init);
module_exit(syscall_release);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159

下面是Makefile文件内容:
# Makefile
obj-m:=hook_open.o
KERNELBUILD:=/lib/modules/$(shell uname -r)/build

default:
make -C $(KERNELBUILD) M=$(shell pwd) modules

clean:
rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions
1
2
3
4
5
6
7
8
9

编译模块 : make 

编译清除:make clean

安装模块 : sudo insmod hook_open.ko 

卸载模块 : sudo rmmod hook_open 

查看模块 : lsmod | grep hook_open
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐