【sylar-webserver】8 HOOK模块
文章目录
- 知识点
- HOOK实现方式
- 非侵入式hook
- 侵入式hook ⭐⭐⭐
- 覆盖系统调用接口
- 获取被全局符号介入机制覆盖的系统调用接口
- 具体实现
- FdCtx 和 FdManager
- connect hook
- do_io模板
在写之前模块的时候,我一直在困惑 协程是如何高效工作的,毕竟协程阻塞线程也就阻塞了。
HOOK模块解开了我的困惑。😎
知识点
HOOK实现方式
动态链接中的hook实现
hook的实现机制,通过动态库的全局符号介入功能,用自定义的接口来替换掉同名的系统调用接口。由于系统调用接口基本上是由C标准函数库libc提供的,所以这里要做的事情就是用自定义的动态库来覆盖掉libc中的同名符号。
基于动态链接的hook有两种方式:
非侵入式hook
第一种是外挂式hook,也称为非侵入式hook,通过优先加自定义载动态库来实现对后加载的动态库进行hook,这种hook方式不需要重新编译代码,考虑以下例子:
#include <unistd.h>
#include <string.h>int main(){write(STDOUT_FILENO, "hello world\n", strlen("hello world\n")); // 调用系统调用write写标准输出文件描述符return 0;
}
编译运行
# gcc main.c
# ./a.out
hello world
ldd命令查看可执行程序的依赖的共享库
# ldd ./a.out linux-vdso.so.1 (0x00007ffde42a4000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f80ec76e000)/lib64/ld-linux-x86-64.so.2 (0x00007f80ecd61000)
可以看到其依赖libc共享库,write系统调用就是由libc提供的。
下面在不重新编译代码的情况下,用自定义的动态库来替换掉可执行程序a.out中的write实现,新建hook.cc
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>ssize_t write(int fd, const void *buf, size_t count) {syscall(SYS_write, STDOUT_FILENO, "12345\n", strlen("12345\n"));
}
gcc -fPIC -shared hook.cc -o libhook.so # 把hook.cc编译成动态库
通过设置 LD_PRELOAD环境变量,将libhoook.so设置成优先加载,从面覆盖掉libc中的write函数,如下:
# LD_PRELOAD="./libhook.so" ./a.out
12345
LD_PRELOAD环境变量,它指明了在运行a.out之前,系统会优先把libhook.so加载到了程序的进程空间,使得在a.out运行之前,其全局符号表中就已经有了一个write符号,这样在后续加载libc共享库时,由于全局符号介入机制,libc中的write符号不会再被加入全局符号表,所以全局符号表中的write就变成了我们自己的实现。⭐
侵入式hook ⭐⭐⭐
libco,libgo 也是使用这种方式
第二种方式的hook是侵入式的,需要改造代码或是重新编译一次以指定动态库加载顺序。
覆盖系统调用接口
unsigned int sleep(unsigned int seconds){...
}
直接写入文件,只需要比 libc 提前链接即可。
获取被全局符号介入机制覆盖的系统调用接口
dslym 函数原型
#define _GNU_SOURCE
#include <dlfcn.h>void *dlsym(void *handle, const char *symbol);
- 链接需要指定
-ldl参数。 - 使用dlsym找回被覆盖的符号,第一个参数固定为
RTLD_NEXT,第二个参数是符号的名称。
具体实现
CMakeLists.txt
set(LIBSsylaryaml-cpppthreaddl
)
extern "C"{// sleep // 定义了函数指针类型 sleep_fun// 该类型对应原生 sleep 函数的签名(接收 unsigned int 参数,返回 unsigned int)typedef unsigned int (*sleep_fun)(unsigned int seconds);// 声明外部的全局函数指针变量 sleep_f,用于保存原始 sleep 函数的地址// 通过 sleep_f 仍能调用原版函数extern sleep_fun sleep_f;
}
#define HOOK_FUN(XX) \XX(sleep)void hook_init(){static bool is_inited = false;if(is_inited){return;}//保存原函数:hook_init() 通过 dlsym(RTLD_NEXT, "sleep") 获取系统原版 sleep 函数的地址,保存到 sleep_f 指针
#define XX(name) name ## _f = (name ## _fun)dlsym(RTLD_NEXT, #name);HOOK_FUN(XX);
#undef XX
}extern "C" {
#define XX(name) name ## _fun name ## _f = nullptr; // 初始化 sleep_fun sleep_f = nullptr;HOOK_FUN(XX);
#undef XX// sleep
unsigned int sleep(unsigned int seconds){if(!sylar::t_hook_enable){return sleep_f(seconds);}sylar::Fiber::ptr fiber = sylar::Fiber::GetThis();sylar::IOManager* iom = sylar::IOManager::GetThis();/*** C++规定成员函数指针的类型包含类信息,即使存在继承关系,&IOManager::schedule 和 &Scheduler::schedule 属于不同类型。* 通过强制转换,使得类型系统接受子类对象iom调用基类成员函数的合法性。* * schedule是模板函数* 子类继承的是模板的实例化版本,而非原始模板* 直接取地址会导致函数签名包含子类类型信息* * std::bind 的类型安全机制* bind要求成员函数指针类型与对象类型严格匹配。当出现以下情况时必须转换:* * 总结,当需要绑定 子类对象调用父类模板成员函数,父类函数需要强转成父类* (存在多继承或虚继承导致this指针偏移)* * 或者* std::bind(&Scheduler::schedule, static_cast<Scheduler*>(iom), fiber, -1)* */iom->addTimer(seconds * 1000 , std::bind((void(sylar::Scheduler::*)(sylar::Fiber::ptr, int thread))&sylar::IOManager::schedule, iom, fiber, -1));sylar::Fiber::GetThis()->yield();return 0;
}
FdCtx 和 FdManager
把 fd 封装一遍,添加非阻塞。
最后再还原会之前的设置
connect hook
do_io模板
/*** 重点 !!!* * 模板函数,通用的 read-write api hook 操作* * Args&& 万能引用,根据传入实参自动推导* * 这里Args,可能是左值,也可能是右值* * std::forward 保持参数的原始值类别 */
template<typename OriginFun, typename ... Args> // 常用⭐
static ssize_t do_io(int fd, OriginFun fun, // hook的原库函数const char* hook_fun_name, // debug输出,hook的函数名uint32_t event, int timeout_so, // 读 / 写 超时 宏标签Args&&... args)
{// Scheduler::run() 设置当前线程是否hookif(!sylar::t_hook_enable){return fun(fd, std::forward<Args>(args)...);}// fd 添加到 FdMgrsylar::FdCtx::ptr ctx = sylar::FdMgr::GetInstance()->get(fd);if(!ctx){return fun(fd, std::forward<Args>(args)...);}// 如果ctx关闭if(ctx->isClose()){errno = EBADF;return -1;}// 不是 socket 或者 用户设定了非阻塞}相关文章:
【sylar-webserver】8 HOOK模块
文章目录 知识点HOOK实现方式非侵入式hook侵入式hook ⭐⭐⭐ 覆盖系统调用接口获取被全局符号介入机制覆盖的系统调用接口 具体实现FdCtx 和 FdManagerconnect hookdo_io模板 在写之前模块的时候,我一直在困惑 协程是如何高效工作的,毕竟协程阻塞线程也就…...
【Tauri2】026——Tauri+Webassembly
前言 不多废话 直言的说,笔者看到这篇文章大佬的文章 【04】Tauri 入门篇 - 集成 WebAssembly - 知乎https://zhuanlan.zhihu.com/p/533025312尝试集成一下WebAssembly,直接开始 正文 准备工作 新建一个项目 安装 vite的rsw插件和rsw pnpm instal…...
Notepad++中将文档格式从Windows(CR LF)转换为Unix(LF)
在Windows中用记事本写了一个.sh的Linux运行脚本,是无法直接在Linux中执行,需要首先把文本编码格式转换为Unix的,特别是换行符这些,转换步骤如下: 1、打开文档 在Notepad中打开需要转换的文件。 2、进入文档格式转换…...
Linux常见工具如yum、vim、gcc、gdb的基本使用,以及编译过程和动静态链接的区别
目录 一、工具的本质 二、一些常用的工具 1.yum 2.vim 1)vim的三种基本模式: 2)vim的基本操作 ①命令模式下的基本操作: ②插入模式: ③底行模式: 3)vim的配置:让他变得更好用 3.gcc…...
【HDFS】EC重构过程中的校验功能:DecodingValidator
一、动机 DecodingValidator是在HDFS-15759中引入的一个用于校验EC数据重构正确性的组件。 先说下引入DecodingValidator的动机,据很多已知的ISSUE(如HDFS-14768, HDFS-15186, HDFS-15240,这些目前都已经fix了)反馈, EC在重构的时候可能会有各种各样的问题,导致数据错误…...
【SAP ME 44】在 HANA DB中报废SFC时的SHOP_ORDER表记录锁定
症状 SELECT…FROM SHOP_ORDER FOR UPDATE 在 SFC 报废期间持有锁,当同时调用数量较大时,可能会导致 HANA 数据库出现大量锁积压。这有时会导致因等待 HANA 数据库释放“选择更新”锁而导致报废 SFC 花费数分钟。 HANA 数据库日志中的示例: # begin PreparedStatement_ex…...
企业级Keepalived高可用离线部署实战(附K8S集群VIP配置)
企业级Keepalived高可用离线部署实战(附K8S集群VIP配置) 摘要:本文详细讲解在离线环境下部署Keepalived实现Kubernetes集群高可用的完整流程,涵盖源码编译安装、多节点配置、健康检查联动等核心环节,并提供生产级参数…...
RBAC的使用
1、简述RBAC的作用及工作流程 Rbac基于角色访问控制,用于管理用户对集群资源的访问权限,通过定义角色和绑定规则,将用户与权限进行关联,作用:权限精细化管理,操作便捷与统一管理,动态调整权限。…...
MySQL+Redis实战教程:从Docker安装部署到自动化备份与数据恢复20250418
MySQLRedis实战教程:从Docker安装部署到自动化备份与数据恢复 一、前言 在企业应用中,对MySQL和Redis运维的要求越来越高: 不能仅是启动就算部署运行稳定、隔离、访问控制、备份恢复、安全可靠,才是 企业级的基本功能 本文将手…...
AI驱动商业变革:零售行业的智能化跃迁
引言:AI技术迈入黄金时代 2024年成为生成式AI(Gen AI)全面落地的关键年。据麦肯锡《技术趋势展望》报告,生成式AI相关投资同比增长7倍,其经济价值预计达2.6-4.4万亿美元[1]。在零售领域,该技…...
linux kernel irq相关函数详解
在Linux内核驱动开发中,处理中断涉及一系列关键函数,正确使用这些函数对确保驱动的稳定性和性能至关重要。以下是disable_irq、free_irq、platform_get_irq和request_irq等函数的详细解析,涵盖其功能、用法、注意事项及示例代码。 一、核心函…...
AI调试工具有哪些?
一、深度学习框架专用调试工具 TensorBoard • 功能:实时监控训练指标(损失值、准确率)、可视化神经网络结构、分析参数分布和梯度信息 • 适用框架:TensorFlow、PyTorch(通过插件) • 特点:支持…...
嵌入式设备网络的动态ID分配机制实现
文章目录 前言一、系统设计要点二、核心数据结构2.1 设备唯一标识(DeviceUID)2.2 节点信息(Node)2.3 节点管理器(NodeManager) 三、核心算法实现3.1 初始化与清理3.1.1 初始化节点管理器3.1.2 清理节点管理器 3.2 动态ID分配策略3.2.1 查找最小可用ID3.2.2 ID使用检查 3.3 心跳…...
交易模式革新:Eagle Trader APP上线,助力自营交易考试效率提升
近年来,金融行业随着投资者需求的日益多样化,衍生出了众多不同的交易方式。例如,为了帮助新手小白建立交易基础,诞生了各类跟单社区;而与此同时,一种备受瞩目的交易方式 —— 自营交易模式,正吸…...
健身会员管理系统(ssh+jsp+mysql8.x)含运行文档
健身会员管理系统(sshjspmysql8.x) 对健身房的健身器材、会员、教练、办卡、会员健身情况进行管理,可根据会员号或器材进行搜索,查看会员健身情况或器材使用情况。...
http、https、TLS、证书原理理解,对称加密到非对称加密问题,以及对应的大致流程
http 超文本传输协议 存在问题: 安全性、隐私性、数据完整性 易被中间人(黑客之类的)对数据进行劫持、篡改、隐私泄露 引出了 https (source) http 在网络模型中的应用层 Application > transport > inter…...
捋一遍Leetcode【hot100】的二叉树专题
二叉树专题 除了后面两个,都挺简单 二叉树的中序遍历 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int …...
[安全实战]Python程序打包为EXE的安全加固全攻略(加密+混淆+签名)
Python程序打包为EXE的安全加固全攻略 (加密+混淆+签名:三位一体的Python程序保护体系) 摘要 本文深度解析Python程序打包为EXE的全流程安全防护方案,涵盖加密算法选择、代码混淆技术、反逆向工程等核心安全策略。通过典型攻击防护方案、商业级加固方案对比,打造企业级…...
【测试文档】项目测试文档,测试管理规程,测试计划,测试文档模版,软件测试报告书(Word)
原件获取列表: 系统测试方案-2.docx B-Web安全服务渗透测试模板.docx 压力测试报告.docx安全测试用例及解析.docx 测试计划.doc 测试需求规范.doc 测试需求指南.docx 测试用例设计白皮.doc 单元测试报告模板.doc 单元测试计划模板.doc 回归测试指南.doc 集成测试报…...
Linux的联网网络管理攻略
RHEL9版本特点 在RHEL7版本中,同时支持network.service和NetworkManager.service(简称NM)。 在RHEL8上默认只能通过NM进行网络配置,包括动态ip和静态ip,若不开启NM,否则无法使用网络RHEL8依然支持network.service&am…...
Zookeeper三台服务器三节点集群部署(docker-compose方式)
1. 准备工作 - 服务器:3 台服务器,IP 地址分别为 `10.10.10.11`、`10.10.10.12`、`10.10.10.13`。 - 安装 Docker:确保每台服务器已安装 Docker 和 Docker Compose。 - 网络通信:确保三台服务器之间可以通过 IP 地址互相访问,并开放以下端口: - `2181`:Zookeeper 客户…...
ISO26262-浅谈用例导出方法和测试方法
目录 1 摘要2 测试方法3 测试用例导出方法4 测试方法与用例导出方法的差异和联系5 结论 1 摘要 ISO26262定义了测试方法和用例导出方法,共同保证产品的开发质量。但在刚开始学习ISO26262的时候,又不是非常清晰地理解它俩的区别和联系。本文主要对它俩的…...
Linux上位机开发实践(SoC和MCU的差异)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 soc一般是指跑linux的芯片,而mcu默认是跑rtos的芯片,两者在基本原理方面其实差异不大。只不过,前者由于性能的原…...
【基于Fluent+Python耦合的热管理数字孪生系统开发:新能源产品开发的硬核技术实践】
引言:热管理数字孪生的技术革命 在新能源领域(如动力电池、储能系统、光伏逆变器等),热管理是决定产品性能与安全的核心问题。传统热设计依赖实验与仿真割裂的流程,而数字孪生技术通过实时数据驱动与动态建模…...
ios app的ipa文件提交最简单的方法
ipa文件是ios的app打包后生成的二级制文件,在上架app store connect或做testflight测试的时候,它提示我们需要使用xcode、transporter或xcode命令行等方式来上传。 而xcode、transporter或xcode命令行的安装都需要使用mac电脑,假如没有mac电…...
详细解释浏览器是如何渲染页面的?
渲染流程概述 渲染的目标:将HTML文本转化为可以看到的像素点 当浏览器的网络线程收到 HTML 文档后,会产生一个渲染任务,并将其传递给渲染主线程的消息队列。在事件循环机制的作用下,渲染主线程取出消息队列中的渲染任务࿰…...
swift-12-Error处理、关联类型、assert、泛型_
一、错误类型 开发过程常见的错误 语法错误(编译报错) 逻辑错误 运行时错误(可能会导致闪退,一般也叫做异常) 2.1 通过结构体 第一步 struct MyError : Errort { var msg: String } 第二步 func divide(_ …...
如何查看HTTP状态码?
目录 一、HTTP状态码查看方法 1. 浏览器开发者工具 2. 命令行工具 3. 服务器日志分析 二、HTTP状态码分类与核心含义 1. 信息类(1xx) 2. 成功类(2xx) 3. 重定向类(…...
下采样(Downsampling)
目录 1. 下采样的定义与作用 2. 常见下采样方法 (1) 池化(Pooling) (2) 跨步卷积(Strided Convolution) (3) 空间金字塔池化(SPP) 3. PyTorch 实现示例 …...
PostgreSQL 常用客户端工具
PostgreSQL 常用客户端工具 PostgreSQL 拥有丰富的客户端工具生态系统,以下是各类常用工具的详细分类和介绍: 一 图形化客户端工具 1.1 跨平台工具 工具名称特点适用场景许可证pgAdmin官方出品,功能全面开发/运维PostgreSQLDBeaver支持多…...
