Linux hook系统调用使你文件无法删除

文章目录

  • 前言
  • 一、什么是hook技术
  • 二、Linux hook种类
  • 三、系统调用表hook
    • 3.1 查看删除文件用到系统调用
    • 3.2 获取系统调用函数
    • 3.3 编写hook函数
    • 3.4 替换hook函数
    • 3.5 测试
  • 参考资料

前言

hook技术在Linux系统安全领域有着广泛的应用,例如通过hook技术可以劫持删除文件的系统调用,从而使用户无法删除特定文件,也可以实现对系统网络,文件,进程等的监控。

一、什么是hook技术

hook技术即钩子函数,钩子的本质是一段用以处理系统消息的程序,。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息(如屏幕取词,监视日志,截获键盘/鼠标输入等),也可以不作处理而继续传递该消息,还可以强制结束消息的传递。也即这项技术就是提供了一个入口,能够针对不同的消息或者API在执行前,先执行你的操作,你的操作也称为[钩子函数]

二、Linux hook种类

三、系统调用表hook

相信大家对某些无法删除的流氓软件都有深刻的印象,下面我们通过一个系统调用表hook来实现该功能。
试验环境:centos,x86,3.10+内核

3.1 查看删除文件用到系统调用

使用strace跟踪文件删除系统调用

strace -o 1.txt rm test

查看输出结果

cat 1.txtexecve("/usr/bin/rm", ["rm", "test"], 0x7ffc8101c548 /* 24 vars */) = 0
brk(NULL)                               = 0xa0f000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0ae12a4000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=87988, ...}) = 0
mmap(NULL, 87988, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f0ae128e000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`&\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2156592, ...}) = 0
mmap(NULL, 3985920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f0ae0cb6000
mprotect(0x7f0ae0e7a000, 2093056, PROT_NONE) = 0
mmap(0x7f0ae1079000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c3000) = 0x7f0ae1079000
mmap(0x7f0ae107f000, 16896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f0ae107f000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0ae128d000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0ae128b000
arch_prctl(ARCH_SET_FS, 0x7f0ae128b740) = 0
access("/etc/sysconfig/strcasecmp-nonascii", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/sysconfig/strcasecmp-nonascii", F_OK) = -1 ENOENT (No such file or directory)
mprotect(0x7f0ae1079000, 16384, PROT_READ) = 0
mprotect(0x60d000, 4096, PROT_READ)     = 0
mprotect(0x7f0ae12a5000, 4096, PROT_READ) = 0
munmap(0x7f0ae128e000, 87988)           = 0
brk(NULL)                               = 0xa0f000
brk(0xa30000)                           = 0xa30000
brk(NULL)                               = 0xa30000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=106172832, ...}) = 0
mmap(NULL, 106172832, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f0ada774000
close(3)                                = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
newfstatat(AT_FDCWD, "test", {st_mode=S_IFREG|0644, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
geteuid()                               = 0
unlinkat(AT_FDCWD, "test", 0)           = 0
lseek(0, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
close(0)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

从上述内容中我们不难看出用户使用rm命令删除文件时,最终是调用了unlinkat实现的删除操作。

3.2 获取系统调用函数

打开内核源码在线阅读网站,搜索sys_unlinkat(系统调用函数一般是sys_*的格式,在搜索时需要添加前缀)

include/linux/syscalls.h文件中找到函数的定义(主要是看一下参数列表)。

在这里插入图片描述

下面我们在系统调用表中找到这个函数的地址,获取它的函数指针。

unsigned long (*orig_unlinkat)(int dfd, const char __user * pathname, int flag);unsigned long *sys_call_table = NULL;
sys_call_table = (unsigned long *)kallsyms_lookup_name("sys_call_table");
if(sys_call_table == NULL) {printk("%s: can not find sys_call_table address\n", __func__);return -1;
}
printk("%s: sys_call_addr = 0x%p\n", __func__, sys_call_table);
orig_unlinkat = sys_call_table[__NR_unlinkat];
printk("%s: _NR_unlinkat = 0x%p\n", __func__, orig_unlinkat);

3.3 编写hook函数

这里我们定义一个hook函数,当文件名称等于"test"返回错误,否则调用unlinkat函数。
这里有2点需要注意:

  • hook函数参数列表必须和原函数完全一致;
  • 在内核空间中无法直接访问用户空间地址的数据,如果要在hook函数中读取参数的值,需要借助copy_from_user先将数据拷贝到内核空间;
asmlinkage long hook_unlinkat(int dfd, const char __user * pathname, int flag)
{char *filename;long ret;// Allocate memory to store the filenamefilename = (char *)kmalloc(PATH_MAX, GFP_KERNEL);if (!filename)return -ENOMEM;// Copy the pathname from userspace to kernelspaceif (copy_from_user(filename, pathname, PATH_MAX)) {kfree(filename);return -EFAULT;}// Check if the filename is the one we want to blockif (strcmp(filename, TARGET_FILENAME) == 0) {printk(KERN_INFO "Attempt to delete %s blocked\n", TARGET_FILENAME);kfree(filename);return -EPERM; // Permission denied}// Call the original unlink syscallret = orig_unlinkat(dfd, pathname, flag);kfree(filename);return ret;
}

3.4 替换hook函数

这里只需要将系统调用表中__NR_unlinkat表项存储的地址替换为我们自己定义的hook函数地址即可。
替换后在用户在使用unlinkat系统调用时会走到我们的hook函数中,经过hook函数处理之后才原来的系统调用函数。
需要注意的是,系统调用表位于内核代码段,在修改系统调用表之前需要先将页表属性修改为可写。

/* make the page writable */
int make_rw(unsigned long address)
{unsigned int level;pte_t *pte = lookup_address(address, &level); //查找虚拟地址所在的页表地址pte->pte |= _PAGE_RW;// 设置页表读写属性return 0;
}/* make the page write protected */
int make_ro(unsigned long address)
{unsigned int level;pte_t *pte = lookup_address(address, &level);pte->pte &= ~_PAGE_RW; //设置只读属性return 0;
}make_rw((unsigned long)sys_call_table); //修改页属性
sys_call_table[__NR_unlinkat] = (unsigned long *)hook_unlinkat; //设置新的系统调用地址
make_ro((unsigned long)sys_call_table);

3.5 测试

加载编译好的内核模块,测试删除test文件
在这里插入图片描述
可以看到在加载了我们编译的模块之后,已经无法删除test文件,这里只是一个示例,通过修改hook函数我们可以实现更多的功能。

参考资料

  1. hook原理介绍与简单实例
  2. Linux hook 机制
  3. Hooking linux内核函数(一):寻找完美解决方案

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/760291.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多源BFS - 01矩阵

LCR 107. 01 矩阵 到最近的0的距离,对每一个非0的位置进行搜索,找到最短的距离即可,但如果对每一个非0的点都进行一次搜索的话,肯定是会超时的。这里可以考虑,将所有0点想象成一个0点(超级0)。然后找到所有1点到超级0的…

第 6 章 ROS-URDF练习(自学二刷笔记)

重要参考: 课程链接:https://www.bilibili.com/video/BV1Ci4y1L7ZZ 讲义链接:Introduction Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程 6.3.4 URDF练习 需求描述: 创建一个四轮圆柱状机器人模型,机器人参数如下,底盘为圆柱…

腾讯云优惠券、代金券、折扣券领取方法及使用教程

腾讯云作为国内领先的云计算服务提供商,一直致力于为广大用户提供高效、稳定、安全的云服务。为了吸引用户上云,腾讯云经常推出各种优惠活动,其中就包括腾讯云优惠券。下面小编将详细介绍腾讯云优惠券的相关信息,包括种类、领取入…

链动3+1模式 全新升级 解决小号和断代问题!!!

随着数字经济的蓬勃发展,市场竞争愈演愈烈,传统的商业模式显得捉襟见肘,难以满足企业快速发展的需求。在这种背景下,一种创新的商业模式——“链动31”应运而生,以其独特的玩法和优势,引领着市场发展的新方…

Python面向对象三大特征(封装、继承、多态)

面向对象编程的三大特征:封装、继承和多态。 注意:在python面向对象编程中,子类对象可以传递给父类类型 一、封装 在Python中,封装是面向对象编程中的一种重要概念,它可以帮助我们实现数据隐藏、信息保护和代码复用。…

阻止默认行为 e.preventDefault()搭配passive:false才有效

正确情况 如果想阻止默认行为,那么 e.preventDefault()搭配passive:false才是正解 document.addEventListener(touchmove,(e)>{ e.preventDefault() console.log(123,123);},{passive:false}) 如果搭配 passive:false,则会报警告 e.preventDefault()搭配passive:true会报…

蓝桥杯-礼物-二分查找

题目 思路 --刚开始想到暴力尝试的方法,但是N太大了,第一个测试点都超时。题目中说前k个石头的和还有后k个石头的和要小于s,在这里要能想到开一个数组来求前n个石头的总重,然后求前k个的直接将sum[i]-sum[i-k-1]就行了&#xff0…

软考中高级案例分析通用答题方法

在软考高级信息系统项目管理师和中级系统集成项目管理工程师考试中,案例分析是一个重要的题型。下面分享几种通用答题方法和个人经验,希望能对大家有所帮助。 历年考试中经常考察的内容 首先,范围管理、进度管理、成本管理、质量管理这四大管…

C++ 子序列

目录 最长递增子序列 摆动序列 最长递增子序列的个数 最长数对链 最长定差子序列 最长的斐波那契子序列的长度 最长等差数列 等差数列划分 II - 子序列 最长递增子序列 300. 最长递增子序列 子数组是连续的,子序列可以不连续,那么就要去[0, i - 1]…

【CKA模拟题】掌握Pod日志输出的秘密

题干 For this question, please set this context (In exam, diff cluster name) 对于这个问题,请设置这个上下文(在考试中,diff cluster name) kubectl config use-context kubernetes-adminkubernetes product pod is running. when you access log…

【算法刷题day1】Leetcode:704. 二分查找、27. 移除元素

Leetcode 704:标准二分查找 文档讲解:代码随想录 题目链接:704.二分查找 状态:稳定输出 题目: 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 n…

在Linux环境底下 用C语言执行Python程序

在Linux环境底下 用C语言执行Python程序 文章目录 在Linux环境底下 用C语言执行Python程序1、环境安装&检测2、C语言调用Python语句2.1 直接调用python语句2.2 调用无参python函数2.3 调用有参python函数 1、环境安装&检测 通过C语言调用Python代码,需要先安…

springboot企业级抽奖项目业务二(用户模块)

书接上回,梅开二度 开发流程 该业务基于rouyi生成好了mapper和service的代码,现在需要在controller层写接口 实际操作流程: 看接口文档一>controller里定义函数一>看给出的工具类一>补全controller里的函数一>运行测试 接口…

【数据结构】堆和树详解堆和二叉树的实现堆的top-k问题

主页:醋溜马桶圈-CSDN博客 专栏:数据结构_醋溜马桶圈的博客-CSDN博客 gitee:mnxcc (mnxcc) - Gitee.com 目录 1.树概念及结构 1.1 树的概念 2.2 树的相关概念 1.3 树的表示 1.4 树在实际中的运用 2.二叉树的概念及结构 2.1 二叉树的概念…

vue前端解析jwt

vue前端解析jwt 我们可以用在线解析看解析的结果:https://www.lddgo.net/encrypt/jwt-decrypt 但是如果在前端需要解析token,拿到其中的权限信息,可以这样解决。 在线的: 完美解决: 代码: function par…

MySQL | 表的约束

目录 1. 空属性 NULL 2. 默认值 DEFAULT 3. 列描述comment 4. zerofill 5. 主键 PRIMARY KEY 6. 自增长AUTO_INCREMENT 7. 唯一键UNIQUE 8. 外键 真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数…

web前端常用标签(html)

1.定义 1.1标签 语法规范&#xff1a;<标签名 属性名"属性值">标签名</标签名> 标签之间可以嵌套 1.2属性 定制元素的行为的。属性是不通用的&#xff0c;每一个标签存在自身的属性。当属性名属性值时&#xff0c;可以只写属性值 2.HTML常用标签 2…

面试笔记——Redis(分布式锁的使用场景及实现原理)

分布式锁的使用场景 资源竞争控制&#xff1a;多个客户端同时访问共享资源时&#xff0c;可以使用分布式锁来控制资源的并发访问&#xff0c;防止多个客户端同时对同一资源进行修改造成数据不一致的问题。 避免重复操作&#xff1a;在分布式环境中&#xff0c;可能会出现多个客…

如何实现手机遥控端关机按钮同时关闭TV端和手机端界面

目前家庭电视机主要通过其自带的遥控器进行操控&#xff0c;实现的功能较为单一。例如&#xff0c;当我们要在TV端搜索节目时&#xff0c;电视机在遥控器的操控下往往只能完成一些字母或数字的输入&#xff0c;而无法输入其他复杂的内容。分布式遥控器将手机的输入能力和电视遥…

基于springboot+vue的智慧生活商城系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…