简介

Linux程序基本都是靠系统调用(syscall)来实现的, 所以可以控制到syscall, 就可以对程序进行监控或修改了;

前置知识

我们知道现在系统中程序分为64位32位的, 系统为了兼容这些程序对系统函数的调用方法进行了简单的区分,最直观的就是64位程序使用syscall来调用系统函数,而32位的程序使用的是int 0x80, 比如这里的sleep函数的系统调用:
64位程序:

32位程序:

当然, 不是简单一个syscall命令或者int 0x80命令就可以完成一个系统调用, 还有一个系统调用号以及相应的参数;
当然我们最关心的是系统调用号, 通过上面的图片我们可以看到同样是sleep函数的调用但是64位和32位的程序的系统调用号是不一样的, 这里64位程序是0xe6,而32位程序是0x197;
具体的系统调用号我们可以通过/usr/include/x86_64-linux-gnu/asm/unistd_32.h/usr/include/x86_64-linux-gnu/asm/unistd_64.h来查看32位和64位的系统调用号:
/usr/include/x86_64-linux-gnu/asm/unistd_32.h部分:


/usr/include/x86_64-linux-gnu/asm/unistd_64.h部分:

有了这些系统调用号, 这些函数具体的地址是被两个不同的系统调用表保存起来的,保存64位系统调用的系统调用表叫sys_call_table,保存32位系统调用的系统调用表叫ia32_sys_call_table;
这两个表的地址我们可以通过/boot/System.map-5.4.0-42-generic来查看:

有了这些表以及系统调用号,我们就可以找到想要的系统call的地址了;
比如要找64位的系统调用nanosleep,就可以用sys_call_table[35]来表示, 因为64位nanosleep的系统调用号是35;而32位的系统调用nanosleep是用ia32_sys_call_table[162]来表示了;

代码实践

现在我们就通过实践的例子来修改一个系统调用, 这里就以sleep函数出发;
sleep函数在底层64位程序通常调用的系统调用是clock_nanosleep, 而32位程序通常调用的系统调用是clock_nanosleep_time64;

内核中查找sys_call_table的地址

在内核查找sys_call_table的地址很容易,通过kallsyms_lookup_name找符号表就可以了:

unsigned long *sys_call_table_64 = 0;
unsigned long *sys_call_table_32 = 0;
sys_call_table_64 = (unsigned long *)(kallsyms_lookup_name("sys_call_table"));
sys_call_table_32 = (unsigned long *)(kallsyms_lookup_name("ia32_sys_call_table"));

修改表中对应的函数

因为内核有安全保护, 我们要修改内存, 需要先将cr0寄存器值中的第17位清0:

    asm volatile("mov %%cr0,%%rax": "=a"(cr0));ret = cr0;cr0 &= 0xfffeffff; //将cr0变量值中的第17位清0asm volatile("mov %%rax,%%cr0" ::"a"(cr0));

然后定义我们自己的函数:

asmlinkage long sys_mycall1(void)
{msleep(1000);return 0;
}

修改表中对应的函数:

#define NUM2 230 //__NR_clock_nanosleep 64位系统调用号为230
#define NUM5 407    //__NR_clock_nanosleep_time64 32位系统调用号为407
sys_call_table_64[NUM2] = (unsigned long)&sys_mycall1;
sys_call_table_32[NUM5] = (unsigned long)&sys_mycall1;

基本的思路就是这样, 然后再做一些完善就可以了;

完整代码

sysfix.c:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/unistd.h>
#include <linux/sched.h>
#include <linux/kallsyms.h>
#include <linux/delay.h>MODULE_LICENSE("Dual BSD/GPL");// 64bit
#define NUM1 35  //__NR_nanosleep 系统调用号为35
#define NUM2 230 //__NR_clock_nanosleep 系统调用号为230//32bit
#define NUM3 162    //__NR_nanosleep 系统调用号为162
#define NUM4 267    //__NR_clock_nanosleep 系统调用号为230
#define NUM5 407    //__NR_clock_nanosleep_time64 系统调用号为407int orig_cr0;
unsigned long *sys_call_table_64 = 0;
unsigned long *sys_call_table_32 = 0;static int (*nanosleep64_addr)(void);
static int (*clock_nanosleep64_addr)(void);
static int (*clock_nanosleep_time64_addr)(void);
static int (*nanosleep32_addr)(void);
static int (*clock_nanosleep32_addr)(void);static int clear_cr0(void)
{unsigned int cr0 = 0;unsigned int ret;asm volatile("mov %%cr0,%%rax": "=a"(cr0));ret = cr0;cr0 &= 0xfffeffff; //将cr0变量值中的第17位清0asm volatile("mov %%rax,%%cr0" ::"a"(cr0));return ret;
}static void setback_cr0(int val)
{asm volatile("mov %%rax,%%cr0" ::"a"(val));
}asmlinkage long sys_mycall1(void)
{msleep(1000);return 0;
}static int __init call_init(void)
{sys_call_table_64 = (unsigned long *)(kallsyms_lookup_name("sys_call_table"));sys_call_table_32 = (unsigned long *)(kallsyms_lookup_name("ia32_sys_call_table"));printk("The sys_call_table_64 address is:%lx\n", (unsigned long)sys_call_table_64);printk("The sys_call_table_32 address is:%lx\n", (unsigned long)sys_call_table_32);printk("call_init......\n");nanosleep64_addr = (int (*)(void))(sys_call_table_64[NUM1]);clock_nanosleep64_addr = (int (*)(void))(sys_call_table_64[NUM2]);nanosleep32_addr = (int (*)(void))(sys_call_table_32[NUM3]);clock_nanosleep32_addr = (int (*)(void))(sys_call_table_32[NUM4]);clock_nanosleep_time64_addr = (int (*)(void))(sys_call_table_32[NUM5]);orig_cr0 = clear_cr0();sys_call_table_64[NUM1] = (unsigned long)&sys_mycall1;sys_call_table_64[NUM2] = (unsigned long)&sys_mycall1;sys_call_table_32[NUM3] = (unsigned long)&sys_mycall1;sys_call_table_32[NUM4] = (unsigned long)&sys_mycall1;sys_call_table_32[NUM5] = (unsigned long)&sys_mycall1;setback_cr0(orig_cr0);return 0;
}static void __exit call_exit(void)
{printk("call_exit......\n");orig_cr0 = clear_cr0();sys_call_table_64[NUM1] = (unsigned long)nanosleep64_addr; //将系统调用恢复sys_call_table_64[NUM2] = (unsigned long)clock_nanosleep64_addr;sys_call_table_32[NUM3] = (unsigned long)nanosleep32_addr;sys_call_table_32[NUM4] = (unsigned long)clock_nanosleep32_addr;sys_call_table_32[NUM5] = (unsigned long)clock_nanosleep_time64_addr;setback_cr0(orig_cr0);
}module_init(call_init);
module_exit(call_exit);MODULE_AUTHOR("cc_sir");
MODULE_VERSION("BETA 1.0");
MODULE_DESCRIPTION("a module for replace a syscall");

Makefile:

KVERS = $(shell uname -r)
# Kernel modules name
obj-m += sysfix.o
# Many file.c
#modulename-objs := file1.o file2.o
# Specify flags for the module compilation.
#EXTRA_CFLAGS=-g -O0
build: kernel_modules
kernel_modules:make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean

Linux syscall Hook相关推荐

  1. Linux内核Hook系统调用execve

    资源下载地址:linux内核hook系统调用execve函数-Linux文档类资源-CSDN下载 (已在内核为 4.19.0-amd64-desktop版本uos编译通过,并成功达到目的) 在Linu ...

  2. linux 系统调用 hook 总结

    1. 系统调用Hook简介 系统调用属于一种软中断机制(内中断陷阱),它有操作系统提供的功能入口(sys_call)以及CPU提供的硬件支持(int 3 trap)共同完成. 我们必须要明白,Hook ...

  3. Linux系统调用Hook姿势总结

    相关学习资料 http://xiaonieblog.com/?post=121 http://hbprotoss.github.io/posts/li-yong-ld_preloadjin-xing- ...

  4. Linux下HOOK动态链接库中API的方法

    2012年,我写了一篇介绍Windows系统下Ring3层API的hook方案--<一种注册表沙箱的思路.实现--Hook Nt函数>,其在底层使用了微软的Detours库.5年后,我又遇 ...

  5. linux 内核 hook函数介绍

    在编写linux内核中的网络模块时,用到了钩子函数也就是hook函数.现在来看看linux是如何实现hook函数的. 先介绍一个结构体: struct nf_hook_ops,这个结构体是实现钩子函数 ...

  6. Linux centos hook,centos7 U盘安装卡在 starting dracut initqueue hook

    U盘安装centos7启动过程中出现:[ok] Reached target Basic System 或者 [ok] starting dracut initqueue hook 到下一行就不动了, ...

  7. linux git hook,前端通过githook一键自动部署项目

    git hook 自动部署 本文章教大家,使用git hook来实现本地开发代码一行命令自动上传到远程服务器. 第一步创建空git仓库 终端进入你需要放项目的文件夹,可以通过ssh root@host ...

  8. linux syscall

    2011-4-18 这部分是在学习电源管理程序时记录的一些碎片 linux内核跟踪 syscall tracer(1) syscall tracer是用于跟踪系统调用的,它会检测所有系统调用的入口和出 ...

  9. linux内核hook技术之指令覆盖与注入

    前言 说到hook,传统意义上,大家都会觉得跟注入和劫持挂钩.在linux内核中,也可以通过指令覆盖和注入的方式进行hook,来完成自己的业务逻辑,实现自己的功能需求. 一部分人喜欢称这种hook技术 ...

最新文章

  1. 深入理解Spring系列之六:bean初始化
  2. Redis集群两种配置方式
  3. java excel添加公式_JAVA实现EXCEL公式专题(四)——字符串函数
  4. IT Monitor
  5. plc维修入门与故障处理实例_电气控制基础+PLC编程入门+工程应用实例
  6. 告别并不遥远的儿时,抬眼期待未来
  7. python卡方检验关键词,特征选择——卡方检验(使用Python sklearn进行实现)
  8. (转)使用JMeter进行Web压力测试
  9. vue项目中打包的相关配置问题
  10. CorelDRAWX4的VBA插件开发(二十六)深度转曲之包含容器内文字转曲
  11. Vue使用debugger
  12. win10计算机系统慢,解决Win10电脑变慢的一些方法
  13. Can't locate Tk.pm
  14. 于 HTML5 WebGL 的民航客机飞行监控系统
  15. 利用Python计算两个地理位置之间的中点
  16. 抖音矩阵系统源码,抖音矩阵系统独立部署定制开发。
  17. vue3 element plus el-input 无法输入问题
  18. 软件项目管理考试大纲
  19. php readfile 图片,php的readfile能读图片吗
  20. Gdevops峰会| 在什么情况下应该考虑换数据库了?

热门文章

  1. word-每一章插入不同的页眉
  2. 20210927-20211003
  3. c#提前感知,看完保证自己再看书不晕车 简单不能再见的基础。
  4. 155款安卓开源项目源码整理,总有你要找的
  5. 果壳游戏(春季每日一题 10)
  6. FAST-LIO论文解读与详细公式推导
  7. 操作系统安装与维护札记(二)BIOS的备份、修改与刷新
  8. 一些手机不能使用HierachyViewer和android.util.Log的问题解决
  9. pcy 算法_大数据分析中的PCY算法
  10. 佳能相机快门卡死的简易维修方法