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

原文链接: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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值