原文链接:http://blog.youkuaiyun.com/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