Linux内核之hook机制:call_void_hook用法实例(六十一)

news2025/1/10 11:16:09

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

    • 🌻1.前言
    • 🌻2.Linux内核之hook机制介绍
      • 🐓2.1 call_void_hook内核源码中定义
      • 🐓2.2 call_void_hook介绍
    • 🌻3.代码实例
      • 🐓3.1 注册钩子函数并调用
      • 🐓3.2 模拟内核注册函数
      • 🐓3.3 自定义钩子函数

🌻1.前言

本篇目的:Linux内核之hook机制:call_void_hook用法实例

🌻2.Linux内核之hook机制介绍

🐓2.1 call_void_hook内核源码中定义

struct hlist_node {
	struct hlist_node *next, **pprev;
};

struct hlist_head {
	struct hlist_node *first;
};

union security_list_options {
	int (*binder_set_context_mgr)(const struct cred *mgr);
	};

struct security_hook_list {
	struct hlist_node		list;
	struct hlist_head		*head;
	union security_list_options	hook;
	char				*lsm;
} __randomize_layout;


struct security_hook_heads {
	struct hlist_head binder_set_context_mgr;
	};
	
	
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
	
#define hlist_entry_safe(ptr, type, member) \
	({ typeof(ptr) ____ptr = (ptr); \
	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
	})	
	
	
#define hlist_for_each_entry(pos, head, member)				\
	for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
	     pos;							\
	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))	

#define call_void_hook(FUNC, ...)				\
	do {							\
		struct security_hook_list *P;			\
								\
		hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \
			P->hook.FUNC(__VA_ARGS__);		\
	} while (0)

🐓2.2 call_void_hook介绍

  • 在Linux内核中,call_void_hook 宏是一种用于调用安全模块钩子的便捷方式。它允许内核代码在特定的钩子点执行所有注册的安全模块回调函数。这种机制是Linux安全模块(LSM)框架的一部分,它允许不同的安全模块以插件的形式加入到内核中,从而提供各种安全特性,如访问控制、审计等。
  • call_void_hook 宏的定义如下:
#define call_void_hook(FUNC, ...)				\
	do {							\
		struct security_hook_list *P;			\
								\
		hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \
			P->hook.FUNC(__VA_ARGS__);		\
	} while (0)
  • 这个宏接受一个钩子函数名 FUNC 和一个可变参数列表 ...。它的工作原理如下:
  1. do { ... } while (0) 构造确保了宏展开后成为一个独立的语句,避免了由于宏展开可能导致的语法错误。
  2. struct security_hook_list *P; 声明了一个指向 security_hook_list 结构的指针 P,这个结构用于表示钩子列表中的元素。
  3. hlist_for_each_entry 宏遍历 &security_hook_heads.FUNC 双链表中的每个元素,并将当前元素赋值给 Phlist_for_each_entry 宏定义了如何从列表中获取条目,并且它使用 hlist_entry_safe 来安全地获取条目。
  4. P->hook.FUNC(__VA_ARGS__); 调用当前钩子列表项中对应的函数 FUNC,并传递 __VA_ARGS__(可变参数)。
  • 在Linux内核中,hlist_nodehlist_head 结构用于实现哈希链表,这是一种内存效率较高的链表实现,特别适用于哈希表。hlist_node 包含指向链表中下一个节点的指针和指向前一个节点的前指针的指针。hlist_head 则包含指向链表第一个节点的指针。
    security_list_options 联合用于存储不同类型的安全钩子函数指针。在 security_hook_list 结构中,hook 字段是一个 security_list_options 类型的联合,用于存储钩子函数的指针。
  • security_hook_heads 结构包含了一个或多个 hlist_head 类型的字段,每个字段对应一个特定的钩子点。在 call_void_hook 宏中,&security_hook_heads.FUNC 表示特定钩子点的钩子列表头。
  • 通过使用 call_void_hook 宏,内核开发者可以在不修改现有代码的情况下,为特定的钩子点添加新的安全检查或操作。这种机制为内核的安全性提供了极大的灵活性和可扩展性。
  • 例如,当内核需要检查是否允许一个进程设置为binder上下文管理器时,它会调用 binder_set_context_mgr 钩子。使用 call_void_hook,内核代码可以这样调用钩子:
call_void_hook(binder_set_context_mgr, current_cred());
  • 这个调用会遍历 security_hook_heads.binder_set_context_mgr 钩子列表,并调用列表中每个钩子项的 binder_set_context_mgr 函数,传递当前进程的凭证作为参数。每个注册的安全模块都会有机会检查这个操作是否允许,并返回相应的结果。

🌻3.代码实例

🐓3.1 注册钩子函数并调用

#include <stdio.h>

// 定义钩子函数的数据结构
struct security_hook_list {
  void (*hook)(int);
};

struct {
  struct security_hook_list FUNC;
} security_hook_heads;

// 定义调用钩子的宏
#define call_void_hook(FUNC, ...)		\
  do {						\
    struct security_hook_list *P;		\
    P = &security_hook_heads.FUNC;		\
    if (P->hook)				\
      P->hook(__VA_ARGS__);			\
  } while (0)

void my_hook_function(int arg) {
  printf("Hook function called with argument: %d\n", arg);
}

int main() {
  // 注册钩子函数
  security_hook_heads.FUNC.hook = my_hook_function;

  // 调用钩子函数
  call_void_hook(FUNC, 42);
  return 0;
}

🐓3.2 模拟内核注册函数

#include <stdio.h>

// 定义钩子函数的数据结构
struct security_hook_list {
  void (*hook)(int);
};

//全局变量 security_hook_heads,其中包含钩子函数的链表
struct {
  struct security_hook_list FUNC;
} security_hook_heads;

// 定义调用钩子的宏
#define call_void_hook(FUNC, ...)		\
  do {						\
    struct security_hook_list *P;		\
    P = &security_hook_heads.FUNC;		\
    if (P->hook)				\
      P->hook(__VA_ARGS__);			\
  } while (0)

void register_hook_in_kernel(void (*hook_func)(int), struct security_hook_list *hook_list) {
  hook_list->hook = hook_func;
}

void my_hook_function(int arg) {
  printf("Hook function called in kernel with argument: %d\n", arg);
}

int main() {
  // 在内核中注册钩子函数
  register_hook_in_kernel(my_hook_function, &security_hook_heads.FUNC);

  // 调用钩子
  call_void_hook(FUNC, 100);
  return 0;
}

🐓3.3 自定义钩子函数

#include <stdio.h>

// 定义钩子函数的数据结构
struct security_hook_list {
  void (*hook)(int);
};

//全局变量 security_hook_heads,其中包含钩子函数的链表
struct {
  struct security_hook_list FUNC;
} security_hook_heads;

// 定义调用钩子的宏
#define call_void_hook(FUNC, ...)		\
  do {						\
    struct security_hook_list *P;		\
    P = &security_hook_heads.FUNC;		\
    if (P->hook)				\
      P->hook(__VA_ARGS__);			\
  } while (0)

void my_hook_function(int arg) {
  printf("Custom hook function called with argument: %d\n", arg);
}

int main() {
  // 注册自定义钩子函数
  security_hook_heads.FUNC.hook = my_hook_function;

  // 调用自定义钩子函数
  call_void_hook(FUNC, 200);

  return 0;
}

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

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

相关文章

使用2023版BurpSuite半自动化Autorize进行垂直越权测试【图文教程】

本人在使用时BurpSuite v2023.12时&#xff0c;查阅网上资料&#xff0c;发现网上大多是旧版&#xff0c;而旧版跟新版在界面上有些许调整。故记录BurpSuite v2023.12使用教程&#xff0c;用于后续本人回顾。 Autorize工具安装 Extensions→BApp Store→Autorize→Download J…

HTML5+CSS3小实例:炫彩荧光线条登录框

实例:炫彩荧光线条登录框 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-sca…

parallels desktop19.3最新版本软件新功能详细介绍

Parallels Desktop是一款运行在Mac电脑上的虚拟机软件&#xff0c;它允许用户在Mac系统上同时运行多个操作系统&#xff0c;比如Windows、Linux等。通过这款软件&#xff0c;Mac用户可以轻松地在同一台电脑上体验不同操作系统的功能和应用程序&#xff0c;而无需额外的硬件设备…

如何在 Flutter 中制作多种颜色的 TextField

TextField widget 本身并不施加任何样式。相反&#xff0c;它会要求 TextEditingController 生成一个样式化的 TextSpan 对象&#xff0c;即一段带有样式的文本。 TextField 将其样式传递给 TextEditingController &#xff0c;默认实现只是将其放入 TextSpan 对象中&#xff0…

揭开ChatGPT面纱(2):OpenAI主类源码概览

文章目录 〇、使用OpenAI的两个步骤一、初始化方法__init__()1.源码2.参数解析 二、提供的接口1.源码2.接口说明主要接口说明 OpenAI版本1.6.1 〇、使用OpenAI的两个步骤 在上一篇博客中&#xff0c;我实现并运行了一个OpenAI的demo&#xff0c;我们可以发现&#xff0c;想要使…

多商家AI智能名片商城系统(开源版)——构建高效数字化商业新生态

一、项目概述 1、项目背景 1&#xff09;起源 随着数字化时代的快速发展&#xff0c;传统名片和商城系统已经难以满足企业日益增长的需求。商家需要更高效、更智能的方式来展示自己的产品和服务&#xff0c;与消费者进行互动和交易。同时&#xff0c;开源技术的普及也为开发…

科林Linux_3 进程

一、进程基础 操作系统基础的执行单元&#xff0c;调度单位 静态数据&#xff1a;只占用磁盘空间&#xff0c;不消耗其他资源 动态数据&#xff1a;磁盘 内存 CPU 1. 编译器将源码编译成一个可执行文件.exe/.elf 2. 运行后系统生成一个同名的进程 程序是进程的静态表现&a…

用 LM Studio 1 分钟搭建可在本地运行大型语言模型平台替代 ChatGPT

&#x1f4cc; 简介 LM Studio是一个允许用户在本地离线运行大型语言模型&#xff08;LLMs&#xff09;的平台&#xff0c;它提供了一种便捷的方式来使用和测试这些先进的机器学习模型&#xff0c;而无需依赖于互联网连接。以下是LM Studio的一些关键特性&#xff1a; 脱机&am…

JavaScript:js基础2

BOM Browser Object Model浏览器对象模型 允许JavaScript与浏览器进行对话 Js将浏览器的各个组成部分封装为对象 可以通过操作BOM对象来实现操作浏览器中的部分 location.href "" //操作浏览器地址栏中的地址BOM中包含了以下对象 window:浏览器窗口对象 Navi…

Leetcode算法训练日记 | day34

专题九 贪心算法 一、K次取反后最大化的数组和 1.题目 Leetcode&#xff1a;第 1005 题 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可以多次选择同一个…

python爬虫 - 爬取html中的script数据(36kr.com新闻信息)

文章目录 1. 分析页面内容数据格式2. 使用re.findall方法&#xff0c;爬取新闻3. 使用re.search 方法&#xff0c;爬取新闻 1. 分析页面内容数据格式 打开 https://36kr.com/ 按F12&#xff08;或 在网页上右键 --> 检查&#xff08;Inspect&#xff09;&#xff09; 找…

HarmonyOS开发案例:【相机开发】

基本概念 相机是OpenHarmony多媒体进程提供的服务之一&#xff0c;提供了相机的录像、预览、拍照功能&#xff0c;支持多用户并发取流。 在进行应用的开发前&#xff0c;开发者应了解以下基本概念&#xff1a; 视频帧 视频流指的是将一系列图片数据按照固定时间间隔排列形成的…

开发日志(20240422):一次以为是跨域但并不是跨域的问题排查记录

1. 日志 在前后端联调的时候&#xff0c;遇到了报错&#xff0c;如下图所示&#xff08;现在再看感觉非常简单了&#xff09;&#xff0c;发现前一个请求通过了&#xff0c;但是第二个请求报错&#xff0c;然后看到 strict-origin-when-cross-origin 条件反射的认为是跨域配置…

iOS - 多线程-GCD-队列组

文章目录 iOS - 多线程-GCD-队列组1. 队列组1.1 基本使用步骤 iOS - 多线程-GCD-队列组 开发过程中&#xff0c;有时候想实现这样的效果 多个任务并发执行所有任务执行完成后&#xff0c;进行下一步处理&#xff08;比如回到主线程刷新UI&#xff09; 1. 队列组 可以使用GC…

探索开源的容器引擎--------------Docker容器操作

目录 一、Docker 容器操作 1.1容器创建 1.2查看容器的运行状态 1.3启动容器 1.4创建并启动容器 1.4.1当利用 docker run 来创建容器时&#xff0c; Docker 在后台的标准运行过程是&#xff1a; 1.4.2在后台持续运行 docker run 创建的容器 1.4.3创建容器并持续运行容器…

Swift-27-类的初始化与销毁

Swift的初始化是一个有大量规则的固定过程。初始化是设置类型实例的操作&#xff0c;包括给每个存储属性初始值&#xff0c;以及一些其他准备工作。完成这个过程后&#xff0c;实例就可以使用了。 简单来讲就是类的构造函数&#xff0c;基本语法如下&#xff1a; 注意&#xff…

3节点ubuntu24.04服务器docker-compose方式部署高可用elk+kafka日志系统并接入nginx日志

一&#xff1a;系统版本: 二&#xff1a;部署环境&#xff1a; 节点名称 IP 部署组件及版本 配置文件路径 机器CPU 机器内存 机器存储 Log-001 10.10.100.1 zookeeper:3.4.13 kafka:2.8.1 elasticsearch:7.7.0 logstash:7.7.0 kibana:7.7.0 zookeeper:/data/zookeep…

贪心算法在单位时间任务调度问题中的应用

贪心算法在单位时间任务调度问题中的应用 一、引言二、问题描述与算法设计三、算法证明四、算法实现与效率分析五、C语言实现示例六、结论 一、引言 单位时间任务调度问题是一类经典的优化问题&#xff0c;旨在分配任务到不同的时间槽中&#xff0c;使得某种性能指标达到最优。…

【JAVA】UDP与TCP套接字编程

目录 一、UDP数据报套接字编程 1、DatagramSocket API 2、DatagramPacket API 3、InetSocketAddress API 4、示例一 5、示例二 二、TCP流套接字编程 1、ServerSocket API 2、Socket API 3、TCP中的长短连接 4、示例一 5、示例二 一、UDP数据报套接字编程 1、Datag…

《ElementPlus 与 ElementUI 差异集合》el-select 显示下拉列表在 Cesium 场景中无法监听关闭

前言 仅在 Element UI 时有此问题&#xff0c;Element Plus 由于内部结构差异较大&#xff0c;不存在此问题。详见《el-select 差异点&#xff0c;如&#xff1a;高、宽、body插入等》&#xff1b; 问题 点击空白处&#xff0c;下拉列表可监听并关闭&#xff1b;但在 Cesium…