Linux syscall Hook
简介
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相关推荐
- Linux内核Hook系统调用execve
资源下载地址:linux内核hook系统调用execve函数-Linux文档类资源-CSDN下载 (已在内核为 4.19.0-amd64-desktop版本uos编译通过,并成功达到目的) 在Linu ...
- linux 系统调用 hook 总结
1. 系统调用Hook简介 系统调用属于一种软中断机制(内中断陷阱),它有操作系统提供的功能入口(sys_call)以及CPU提供的硬件支持(int 3 trap)共同完成. 我们必须要明白,Hook ...
- Linux系统调用Hook姿势总结
相关学习资料 http://xiaonieblog.com/?post=121 http://hbprotoss.github.io/posts/li-yong-ld_preloadjin-xing- ...
- Linux下HOOK动态链接库中API的方法
2012年,我写了一篇介绍Windows系统下Ring3层API的hook方案--<一种注册表沙箱的思路.实现--Hook Nt函数>,其在底层使用了微软的Detours库.5年后,我又遇 ...
- linux 内核 hook函数介绍
在编写linux内核中的网络模块时,用到了钩子函数也就是hook函数.现在来看看linux是如何实现hook函数的. 先介绍一个结构体: struct nf_hook_ops,这个结构体是实现钩子函数 ...
- Linux centos hook,centos7 U盘安装卡在 starting dracut initqueue hook
U盘安装centos7启动过程中出现:[ok] Reached target Basic System 或者 [ok] starting dracut initqueue hook 到下一行就不动了, ...
- linux git hook,前端通过githook一键自动部署项目
git hook 自动部署 本文章教大家,使用git hook来实现本地开发代码一行命令自动上传到远程服务器. 第一步创建空git仓库 终端进入你需要放项目的文件夹,可以通过ssh root@host ...
- linux syscall
2011-4-18 这部分是在学习电源管理程序时记录的一些碎片 linux内核跟踪 syscall tracer(1) syscall tracer是用于跟踪系统调用的,它会检测所有系统调用的入口和出 ...
- linux内核hook技术之指令覆盖与注入
前言 说到hook,传统意义上,大家都会觉得跟注入和劫持挂钩.在linux内核中,也可以通过指令覆盖和注入的方式进行hook,来完成自己的业务逻辑,实现自己的功能需求. 一部分人喜欢称这种hook技术 ...
最新文章
- 深入理解Spring系列之六:bean初始化
- Redis集群两种配置方式
- java excel添加公式_JAVA实现EXCEL公式专题(四)——字符串函数
- IT Monitor
- plc维修入门与故障处理实例_电气控制基础+PLC编程入门+工程应用实例
- 告别并不遥远的儿时,抬眼期待未来
- python卡方检验关键词,特征选择——卡方检验(使用Python sklearn进行实现)
- (转)使用JMeter进行Web压力测试
- vue项目中打包的相关配置问题
- CorelDRAWX4的VBA插件开发(二十六)深度转曲之包含容器内文字转曲
- Vue使用debugger
- win10计算机系统慢,解决Win10电脑变慢的一些方法
- Can't locate Tk.pm
- 于 HTML5 WebGL 的民航客机飞行监控系统
- 利用Python计算两个地理位置之间的中点
- 抖音矩阵系统源码,抖音矩阵系统独立部署定制开发。
- vue3 element plus el-input 无法输入问题
- 软件项目管理考试大纲
- php readfile 图片,php的readfile能读图片吗
- Gdevops峰会| 在什么情况下应该考虑换数据库了?