Linux/Ubuntu18.04 下添加系统调用的两种方法 (内核编译法|模块添加)

吐槽一下操作系统实践,教材代码全是内核3.3之前的版本。。。

记录一下系统调用的实验,希望对各位有所帮助。

方法一:内核编译法

这里我给一个链接,这个博客写的很好,能顺利运行(失败的话就是自己的操作有问题):https://blog.csdn.net/qq_41175905/article/details/80529245

 

方法二:通过module进行内核添加

1.这里在任何一个文件夹下编写即可

2.以hello.c为例,这里我看了一些博客,直接拿他们代码过来用了,只不过需要需要修改一些旧的版本,例如movl写成movq,寄存器eax写成rax,cr0 &= 0xfffeffff应该写成0xfffffffffffeffff,就是添加8个f。

需要注意的时,下面sys_call_table的地址应该修改为你的电脑此时此刻显示的地址,0x不能省略,同时每次重启地址都会变化。

查询syscall_table地址的命令为:

sudo cat /proc/kallsyms | grep sys_call_table

  hello.c

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/unistd.h>
#include <linux/sched.h>



MODULE_LICENSE("Dual BSD/GPL");

#define SYS_CALL_TABLE_ADDRESS 0xffffffffa04001a0  //sys_call_table对应的地址
#define NUM 223  //系统调用号为223
int orig_cr0;  //用来存储cr0寄存器原来的值
unsigned long *sys_call_table_my=0;

static int(*anything_saved)(void);  //定义一个函数指针,用来保存一个系统调用

static int clear_cr0(void) //使cr0寄存器的第17位设置为0(内核空间可写)
{
    unsigned int cr0=0;
    unsigned int ret;
    asm volatile("movq %%cr0,%%rax":"=a"(cr0));//将cr0寄存器的值移动到eax寄存器中,同时输出到cr0变量中
    ret=cr0;
    cr0&=0xfffffffffffeffff;//将cr0变量值中的第17位清0,将修改后的值写入cr0寄存器
    asm volatile("movq %%rax,%%cr0"::"a"(cr0));//将cr0变量的值作为输入,输入到寄存器eax中,同时移动到寄存器cr0中
    return ret;
}

static void setback_cr0(int val) //使cr0寄存器设置为内核不可写
{
    asm volatile("movq %%rax,%%cr0"::"a"(val));
}

asmlinkage long sys_mycall(void) //定义自己的系统调用
{   
    printk("模块系统调用-当前pid:%d,当前comm:%s\n",current->pid,current->comm);
    printk("hello,world!\n");
    return current->pid;    
}
static int __init call_init(void)
{
    sys_call_table_my=(unsigned long*)(SYS_CALL_TABLE_ADDRESS);
    printk("call_init......\n");
    anything_saved=(int(*)(void))(sys_call_table_my[NUM]);//保存系统调用表中的NUM位置上的系统调用
    orig_cr0=clear_cr0();//使内核地址空间可写
    sys_call_table_my[NUM]=(unsigned long) &sys_mycall;//用自己的系统调用替换NUM位置上的系统调用
    setback_cr0(orig_cr0);//使内核地址空间不可写
    return 0;
}

static void __exit call_exit(void)
{
    printk("call_exit......\n");
    orig_cr0=clear_cr0();
    sys_call_table_my[NUM]=(unsigned long)anything_saved;//将系统调用恢复
    setback_cr0(orig_cr0);
}

module_init(call_init);
module_exit(call_exit);

3.Makefile文件的编写(M必须大写)

obj-m:=hello.o
CURRENT_PATH:=$(shell pwd)
LINUX_KERNEL_PATH:=/usr/src/linux-headers-4.15.0-46-generic
all:
	make -C  $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
	make -C  $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

依次输入如下命令:

sudo make
sudo insmod hello.ko
lsmod //查看hello是否插入模块

4.编写测试c文件

#include<stdio.h>
#include<stdlib.h>
#include<linux/kernel.h>
#include<sys/syscall.h>
#include<unistd.h>

int main()
{
        unsigned long x = 0;
        x = syscall(223);        //测试223号系统调用
        printf("图灵-1627405131 syscall result: %ld\n", x);
        return 0;
}

212

 

  • 6
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
编译内核时,首先需要安装所需的编译工具和依赖项。在 Ubuntu 18.04 中,可以通过以下命令安装必要的软件包: ``` sudo apt-get install build-essential libncurses-dev bison flex libssl-dev libelf-dev ``` 接下来,您可以按照以下步骤编译内核: 1. 获取内核源代码。您可以从官方网站下载源代码包,或者使用 git 克隆内核代码仓库。例如,使用以下命令克隆官方源代码: ``` git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git ``` 2. 进入源代码目录: ``` cd linux-stable ``` 3. 配置内核选项。您可以使用现有的内核配置文件,也可以从头开始配置。如果想使用现有的配置文件,可以运行: ``` cp /boot/config-$(uname -r) .config ``` 然后运行以下命令打开配置界面: ``` make menuconfig ``` 在配置界面中,可以根据需要进行修改和调整。 4. 编译内核。运行以下命令开始编译: ``` make -j$(nproc) ``` 这将使用所有可用的处理器核心并行编译内核。 5. 安装编译好的内核。运行以下命令安装编译好的内核镜像和模块: ``` sudo make modules_install install ``` 这将安装内核系统中,并更新引导配置。 6. 重新启动系统。完成安装后,重新启动计算机并选择新编译内核启动。 请注意,编译内核可能需要一些时间和磁盘空间。另外,如果您对内核配置不熟悉,建议在编译前先备份现有的内核配置文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值