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.rhkb.cn/news/281213.html

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

相关文章

Unity Live Capture 中实现面部捕捉同步模型动画

Unity Face Capture 是一个强大的工具,可以帮助你快速轻松地将真实人脸表情捕捉到数字模型中。在本文中,我们将介绍如何在 Unity Face Capture 中实现面部捕捉同步模型动画。 安装 |实时捕获 |4.0.0 (unity3d.com) 安装软件插件 安装 Live Capture 软件…

C++利用开散列哈希表封装unordered_set,unordered_map

C利用开散列哈希表封装unordered_set,unordered_map 一.前言1.开散列的哈希表完整代码 二.模板参数1.HashNode的改造2.封装unordered_set和unordered_map的第一步1.unordered_set2.unordered_map 3.HashTable 三.string的哈希函数的模板特化四.迭代器类1.operator运算符重载1.动…

【Node.js从基础到高级运用】十三、NodeJS中间件高级应用

在现代web开发中,Node.js因其高效和灵活性而备受青睐。其中,中间件的概念是构建高效Node.js应用的关键。在这篇博客文章中,我们将深入探讨Node.js中间件的高级应用,包括创建自定义中间件、使用第三方中间件等。我们将从基础讲起&a…

旅游小程序在旅游营销中的作用及其优势

一、引言部分 随着科技的发展,移动互联网已经成为我们日常生活的一部分。对于旅游业来说,这也意味着新的机遇和挑战。其中,旅游小程序的出现为旅游业带来了全新的营销方式。本文将深入探讨旅游小程序在旅游营销中的作用以及其具体优势。 二、…

day12-SpringBootWeb 登录认证

一、登录功能 Slf4j RestController public class LoginController {Autowiredprivate EmpService empService;PostMapping("/login")public Result login(RequestBody Emp emp){log.info("员工登录: {}", emp);Emp e empService.login(emp);//登录失败, …

Java小项目--满汉楼

Java小项目–满汉楼 项目需求 项目实现 1.实现对工具包的编写 先创建libs包完成对jar包的拷贝和添加入库 德鲁伊工具包 package com.wantian.mhl.utils;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource; import java.io.FileInputStream…

C# 设置AutoScroll为true没效果的原因分析和解决办法

C#中添加tabControl 分页,将autoscroll设置为true发现缩小窗口没有滚动条效果。该问题出现后,检索发现也有很多人询问了该问题,但是都没有给出解决方案。 原因是内部button的属性Anchor设置为top、left、right、bottom导致的缩小界面窗口也没…

QT_day2:2024/3/21

作业1:使用QT完成一个登录界面 要求: 1. 需要使用Ui界面文件进行界面设计 2. ui界面上的组件相关设置,通过代码实现 3. 需要添加适当的动图 源代码: #include "widget.h" #include "ui_widget.h"Widget…

数据结构:链式二叉树

对于二叉树而言,如果不是完全二叉树,就不再适合用数组存储了 在任意二叉树中,度为0的节点都比度为2的节点多1个,即 n0 n2 1 二叉树结构 typedef struct BinTreeNode {int val;struct BinTreeNode* left;struct BinTreeNode* right; }BTNode; 二叉树…

MySQL高级学习笔记

1、MySQL架构组成 1.1 高级MySQL介绍 什么是DBA? 数据库管理员,英文是Database Administrator,简称DBA; 百度百科介绍 数据库管理员(简称DBA),是从事管理和维护数据库管理系统(D…

算法系列--递归

一.如何理解递归 递归对于初学者来说是一个非常抽象的概念,笔者在第一次学习时也是迷迷糊糊的(二叉树遍历),递归的代码看起来非常的简洁,优美,但是如何想出来递归的思路或者为什么能用递归这是初学者很难分析出来的 笔者在学习的过程中通过刷题,也总结出自己的一些经验,总结来…

【什么是Internet?网络边缘,网络核心,分组交换 vs 电路交换,接入网络和物理媒体】

文章目录 一、什么是Internet?1.从具体构成角度来看2.从服务角度来看 二、网络结构1.网络边缘1.网络边缘:采用网络设施的面向连接服务1.1.目标:在端系统之间传输数据1.2.TCP服务 2.网络边缘:采用网络设施的无连接服务2.1目标&…

探讨Java代码混淆加固工具

摘要 本篇博客将介绍几种常用的Java代码混淆工具,如ProGuard、Allatori Java Obfuscator、VirboxProtector、ipaguard和DashO。我们将深入探讨它们的特点、功能以及在保护Java应用程序安全方面的作用。此外,还将强调在使用Java代码混淆工具时需要注意的…

openssl3.2 - note - Decoders and Encoders with OpenSSL

文章目录 openssl3.2 - note - Decoders and Encoders with OpenSSL概述笔记编码器/解码器的调用链OSSL_STORE 编码器/解码器的名称和属性OSSL_FUNC_decoder_freectx_fnOSSL_FUNC_encoder_encode_fn官方文档END openssl3.2 - note - Decoders and Encoders with OpenSSL 概述 …

‍Java OCR技术全面解析:六大解决方案比较

博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通鸿蒙》 …

[ C++ ] STL---stack与queue

目录 stack简介 stack的常用接口 queue简介 queue的常用接口 stack的模拟实现 queue的模拟实现 stack简介 1. stack是具有后进先出操作的一种容器适配器,其只能从容器的一端进行元素的插入与删除操作; 2. stack是作为容器适配器被实现的&#xff0…

ubuntu20.04搭建rtmp视频服务

1.安装软件 sudo apt-get install ffmpeg sudo apt-get install nginx sudo apt-get install libnginx-mod-rtmp 2.nginx配置 修改/etc/nginx/nginx.conf文件,在末尾添加: rtmp {server {listen 1935;application live {live on;}} } 3.视频测试 本…

使用 ZipArchiveInputStream 读取压缩包内文件总数

读取压缩包内文件总数 简介 ZipArchiveInputStream 是 Apache Commons Compress 库中的一个类,用于读取 ZIP 格式的压缩文件。在处理 ZIP 文件时,编码格式是一个重要的问题,因为它决定了如何解释文件中的字符数据。通常情况下,Z…

权限管理系统-0.5.0

六、审批管理模块 审批管理模块包括审批类型和审批模板&#xff0c;审批类型如&#xff1a;出勤、人事、财务等&#xff0c;审批模板如&#xff1a;加班、请假等具体业务。 6.1 引入依赖 在项目中引入activiti7的相关依赖&#xff1a; <!--引入activiti的springboot启动器…

TikTok美国本土小店如何运营?常见小白问题解答

作为资深跨境老玩家&#xff0c;虽不说是经验丰富&#xff0c;至少也是摸清了基本的玩法思路。TikTok作为近来的跨境新蓝海&#xff0c;他的玩法其实并不难&#xff0c;作为第一批试错玩家&#xff0c;今天也诚心给大家分享一些美国本土小店运营经验&#xff0c;感兴趣的话就看…