截获或替换linux系统调用

2023-05-16

     直接上代码吧:

     hello.c:

#include <linux/kernel.h> /*Needed by all modules*/
#include <linux/module.h> /*Needed for KERN_* */
#include <linux/init.h> /* Needed for the macros */
#include <linux/syscalls.h> //包含系统调用的相关定义和声明
//若要打印相关目录,则需要包含以下的头文件
#include <linux/fs.h>
#include <linux/fs_struct.h>
#include <linux/dcache.h>
#include <linux/path.h>

//内核开发者容不得闭源,所以要想利用内核编程,必须包含这个宏定义
MODULE_LICENSE("GPL");

//内核为了安全,虽然内核符号表导出了sys_call_table,但是不能直接使用
//否则,加载模块会报“未定义的符号”错误信息,所以,我们直接使用
//sys_call_table的内核地址,用cat /proc/kallsyms | grep sys_call_table
//命令可以找到他的内核地址:c165e140 R sys_call_table
//这里还有一个注意点,就是R表明其是只读的,所以我们要想替换系统调用(就必须
//写入我们自己的函数以替换内核系统调用,这里需要写的权限),后面我们将看到,
//我们在内核态改变了cr0寄存器的WP标志位,令其为0从而允许写操作。
#define SYS_TAB 0xc165e140

//指向系统调用数组
unsigned long* sys_call_table = (unsigned long*)SYS_TAB;
int (*orig_mkdir)(void);

unsigned int clear_and_return_cr0(void);
void setback_cr0(unsigned int val);
int orig_cr0;

asmlinkage int my_mkdir(const char *path)
{
    //获取当前进程的id
    int pid = current->pid;
    //获取当前进程的父进程id
    int ppid = current->real_parent->real_parent->pid;
    //获取当前进程的根目录
    const char *ppwd = (current->fs->root).dentry->d_name.name;
    struct path pwd;
    //获取当前目录
    get_fs_pwd(current->fs,&pwd);
    printk(KERN_WARNING "Warnning Someone(PID=%d,parent=%d) attempts to mkdir!\n",pid,ppid);
    printk(KERN_WARNING "ROOT:%s!\n",ppwd);
    printk(KERN_WARNING "PWD:%s!\n",pwd.dentry->d_name.name);
    return 0;
}

int hello_init(void)
{
    printk(KERN_WARNING "Hello kernel, it's %d!\n",2014);
   
    //清cr0的WP位
    orig_cr0 = clear_and_return_cr0();
    //保存原系统调用
    orig_mkdir=(int (*)(void))sys_call_table[__NR_mkdir];
    //等价sys_call_table[__NR_mkdir]=(unsigned long)&my_mkdir;
    //替换成我们自己的函数
    sys_call_table[__NR_mkdir]=(unsigned long)my_mkdir;
    //为了内核安全,恢复cr0的WP位
    setback_cr0(orig_cr0);
    return 0;
}


void hello_exit(void)
{
    printk("Bye, kernel!");
    orig_cr0 = clear_and_return_cr0();
    //恢复原系统调用
    sys_call_table[__NR_mkdir]=(unsigned long)orig_mkdir;
    setback_cr0(orig_cr0);
}

unsigned int clear_and_return_cr0(void)
{
    unsigned int cr0 = 0;
    unsigned int ret;
    asm volatile ("movl %%cr0, %%eax": "=a"(cr0));
    ret = cr0;
    /*clear the 20th bit of CR0,*/
    cr0 &= 0xfffeffff;
    asm volatile ("movl %%eax, %%cr0"::"a"(cr0));
    return ret;
}

void setback_cr0(unsigned int val)
{
    asm volatile ("movl %%eax, %%cr0": : "a"(val));
}
/* main module function*/
module_init(hello_init);
module_exit(hello_exit);

Makefile文件:

obj-m := hello.o

all:
    $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
    $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean


    把hello.c文件和Makefile文件放在同一个目录之下,执行make命令,即可得到hello.ko,以root权限执行insmod ./hello.ko。然后用lsmod | grep hello命令可看到此模块已经加载了。tail /var/log/kern.log命令可以查看代码中的printk输出。好了,我们执行mkdir adf命令想新建目录,但是相应的目录不会被创建,而且kern.log中会有相应的输出。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

截获或替换linux系统调用 的相关文章

随机推荐

  • Linux0.11 进程0

    Linux中1号进程是由0号进程来创建的 xff0c 因此必须要知道的是如何创建0号进程 xff0c 由于在创建进程时 xff0c 程序一直运行在内核态 xff0c 而进程运行在用户态 xff0c 因此创建0号进程涉及到特权级的变化 xff
  • Linux0.11 由进程睡眠函数sleep_on()中的堆栈变量tmp引发的思考 关于进程内核堆栈

    sleep on cpp view plaincopy 功能 xff1a 当前进程进入不可中断睡眠态 xff0c 挂起在等待队列上 参数 xff1a p 等待队列头 返回 xff1a xff08 无 xff09
  • 关于Windows系统环境变量的引用问题

    做Leap Motion开发时 xff0c 新建了LEAP SDK的系统环境变量 xff0c 按照官方SDK文档中说明的 xff0c 在工程中引入 LEAP SDK include 之前半年的时间里都是这样做的 xff0c 没有任何问题 x
  • 深入理解Linux内核--信号

    信号用于在用户态进程间通信 内核也用信号通知进程系统所发生的事情 1 信号的作用 信号 signal 是很短的消息 xff0c 可以被发送到一个进程或一组进程 发送给进程的唯一信息通常是一个数 xff0c 以此来标识信号 使用信号的两个主要
  • 进程上下文与中断上下文

    处理器总处于以下状态中的一种 xff1a xff11 内核 态 xff0c 运行于进程 上下文 xff0c 内核代表进程运行于内核空间 xff12 内核态 xff0c 运行于中断上下文 xff0c 内核代表硬件运行于内核空间 xff13 用
  • 进程上下文VS中断上下文

    内核空间和用户空间是现代操作 系统的两种工作模式 xff0c 内核模块运行在内核空间 xff0c 而用户态应用程序运行在用户空间 它们代表不同的级别 xff0c 而对系统资源具有不同的访问权限 内核模块运行在最高级别 xff08 内核态 x
  • 中断不可睡眠的一些理解

    一 LINUX中到是有中断还没有完全返回就调用schedule 而睡眠过去的例子 可以猜是哪里 我觉得 xff0c 中断和异常不同 xff0c 中断是异步的 xff0c 异常和系统调用是同步的 异常比如缺页异常发生时 xff0c 当前任务在
  • kmalloc和vmalloc

  • linux内核中内存相关的操作函数

    1 kmalloc kfree static always inline void kmalloc size t size gfp t flags 内核空间申请指定大小的内存区域 xff0c 返回内核空间虚拟地址 在函数实现中 xff0c
  • Oracle安全:SCN可能最大值与耗尽问题Oracle安全:SCN可能最大值与耗尽问题

    SCN的问题一旦出现 xff0c 使得数据库的一切事务停止 xff0c 由于SCN不能后退 xff0c 所以数据库必须重建 xff0c 才能够重用 在2012年第一季度的CPU补丁中 xff0c 包含了一个关于SCN修正的重要变更 xff0
  • Linux内核 申请和释放内存流程

    1 内核初始化 xff1a 内核建立好内核页目录页表数据库 xff0c 假设物理内存大小为len xff0c 则建立了 3G 3G 43 len 0 len 这样的虚地址vaddr和物理地址paddr的线性对应关系 xff1b 内核建立一个
  • 编译器"自举与移植"原理

    本文基于对 编译原理与实践 中有关编译器自举与移植部分的读书 笔记 形式 xff0c 因为原书是老外写的 xff0c 感觉翻译的地方好多语句不通或难以理解 xff0c 所以花了好多功夫研究这一块 注 xff1a 本文中与原书一致的地方都是P
  • Linux 内核 由block_read和block_write函数引发的设备块号转换问题的思考

    在1 2内核版本中 xff0c 在Linux fs目录下 xff0c 有一个block dev c文件 xff0c 里面主要包含了block read block write block fsync函数 先说说我遇到的问题 xff0c 在块
  • Linux 进程调度时机

    Linux调度时机主要 有 xff1a 1 进程状态转换的时刻 xff1a 进程终止 进程睡眠 2 当前进程的时间 片用完时 xff08 current gt counter 61 0 xff09 3 设备驱动程序 4 进程从中断 异常及系
  • linux 下批量转换pdf的命令方法

    由于在windows下的图形界面 xff0c 难以批量进行其他格式的文件到PDF格式文件的转换 xff0c 而一些其他的软件也不是很满意 xff0c 所以转到linux下 xff0c 想利用linux强大的命令行来完成这件事 linux下有
  • Linux内核 内存映射文件机制mmap

    今天研究Linux1 2内核运行加载a out格式的可执行文件的代码时 xff0c 无意中研究明白了内核提供的内存映射机制 mmap xff08 memory map xff09 当内核要加载可执行文件到相应的用户地址空间时 xff0c 有
  • bash提示符的配置:

    bash提示符的配置 xff1a 如果您很容易使 shell 提示行变得色彩绚烂斓且带有更多信息 xff0c 为什么还要坚持用单调的标准 shell 提示行呢 xff1f 在这篇技巧中 xff0c Daniel Robbins 将说明如何获
  • Linux线性地址空间的划分及内核寻址方式

    今天研究Linux1 2内核时 xff0c 注意到该版本中的PAGE OFFSET宏被定义为0 xff0c 考虑到进程的地址空间被划分为3G的用户态地址空间和1G的内核态地址空间 xff0c 于是深入的研究了一下这个问题 一开始我只是疑惑
  • linux 最简单的模块的编写和运行

    第一次动手编写一个内核模块 xff0c 但是查找了许多资料没有一个可以完美通过编译的 xff0c 郁闷 xff0c 最后还是解决了 xff0c 分享出来 首先是hello c include lt linux kernel h gt Nee
  • 截获或替换linux系统调用

    直接上代码吧 xff1a hello c include lt linux kernel h gt Needed by all modules include lt linux module h gt Needed for KERN inc