当前位置: 首页 > news >正文

7.5 Windows驱动开发:监控Register注册表回调

在笔者前一篇文章《内核枚举Registry注册表回调》中实现了对注册表的枚举,本章将实现对注册表的监控,不同于32位系统在64位系统中,微软为我们提供了两个针对注册表的专用内核监控函数,通过这两个函数可以在不劫持内核API的前提下实现对注册表增加,删除,创建等事件的有效监控,注册表监视通常会通过CmRegisterCallback创建监控事件并传入自己的回调函数,与该创建对应的是CmUnRegisterCallback当注册表监控结束后可用于注销回调。

CmRegisterCallback和CmUnRegisterCallback是Windows操作系统提供的两个内核API函数,用于注册和取消注册注册表回调函数。

注册表回调函数是一种内核回调函数,它可以用于监视和拦截系统中的注册表操作,例如键值的创建、修改和删除等。当有相关操作发生时,操作系统会调用注册的注册表回调函数,并将操作相关的信息传递给回调函数。

CmRegisterCallback函数用于注册注册表回调函数,而CmUnRegisterCallback函数则用于取消注册已经注册的回调函数。开发者可以在注册表回调函数中执行自定义的逻辑,例如记录日志、过滤敏感数据、或者阻止某些操作。

需要注意的是,注册表回调函数的注册和取消注册必须在内核模式下进行,并且需要开发者有一定的内核开发经验。同时,注册表回调函数也需要遵守一些约束条件,例如不能阻塞或挂起进程或线程的创建或访问,不能调用一些内核API函数等。

内核监控Register注册表回调在安全软件、系统监控和调试工具等领域有着广泛的应用。开发者可以利用这个机制来监视和拦截系统中的注册表操作,以保护系统安全。

  • CmRegisterCallback 设置注册表回调
  • CmUnRegisterCallback 注销注册表回调

默认情况下CmRegisterCallback需传入三个参数,参数一回调函数地址,参数二空余,参数三回调句柄,微软定义如下。

// 参数1:回调函数地址
// 参数2:无作用
// 参数3:回调句柄
NTSTATUS CmRegisterCallback([in]           PEX_CALLBACK_FUNCTION Function,[in, optional] PVOID                 Context,[out]          PLARGE_INTEGER        Cookie
);

自定义注册表回调函数MyLySharkCallback需要保留三个参数,CallbackContext回调上下文,Argument1是操作类型,Argument2定义详细结构体指针。

NTSTATUS MyLySharkCallback(_In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2)

在自定义回调函数内Argument1则可获取到操作类型,类型是一个REG_NOTIFY_CLASS枚举结构,微软对其的具体定义如下所示。

typedef enum _REG_NOTIFY_CLASS {RegNtDeleteKey,RegNtPreDeleteKey = RegNtDeleteKey,RegNtSetValueKey,RegNtPreSetValueKey = RegNtSetValueKey,RegNtDeleteValueKey,RegNtPreDeleteValueKey = RegNtDeleteValueKey,RegNtSetInformationKey,RegNtPreSetInformationKey = RegNtSetInformationKey,RegNtRenameKey,RegNtPreRenameKey = RegNtRenameKey,RegNtEnumerateKey,RegNtPreEnumerateKey = RegNtEnumerateKey,RegNtEnumerateValueKey,RegNtPreEnumerateValueKey = RegNtEnumerateValueKey,RegNtQueryKey,RegNtPreQueryKey = RegNtQueryKey,RegNtQueryValueKey,RegNtPreQueryValueKey = RegNtQueryValueKey,RegNtQueryMultipleValueKey,RegNtPreQueryMultipleValueKey = RegNtQueryMultipleValueKey,RegNtPreCreateKey,RegNtPostCreateKey,RegNtPreOpenKey,RegNtPostOpenKey,RegNtKeyHandleClose,RegNtPreKeyHandleClose = RegNtKeyHandleClose,//// .Net only//    RegNtPostDeleteKey,RegNtPostSetValueKey,RegNtPostDeleteValueKey,RegNtPostSetInformationKey,RegNtPostRenameKey,RegNtPostEnumerateKey,RegNtPostEnumerateValueKey,RegNtPostQueryKey,RegNtPostQueryValueKey,RegNtPostQueryMultipleValueKey,RegNtPostKeyHandleClose,RegNtPreCreateKeyEx,RegNtPostCreateKeyEx,RegNtPreOpenKeyEx,RegNtPostOpenKeyEx,//// new to Windows Vista//RegNtPreFlushKey,RegNtPostFlushKey,RegNtPreLoadKey,RegNtPostLoadKey,RegNtPreUnLoadKey,RegNtPostUnLoadKey,RegNtPreQueryKeySecurity,RegNtPostQueryKeySecurity,RegNtPreSetKeySecurity,RegNtPostSetKeySecurity,//// per-object context cleanup//RegNtCallbackObjectContextCleanup,//// new in Vista SP2 //RegNtPreRestoreKey,RegNtPostRestoreKey,RegNtPreSaveKey,RegNtPostSaveKey,RegNtPreReplaceKey,RegNtPostReplaceKey,MaxRegNtNotifyClass //should always be the last enum
} REG_NOTIFY_CLASS;

其中对于注册表最常用的监控项为以下几种类型,当然为了实现监控则我们必须要使用之前,如果使用之后则只能起到监视而无法做到监控的目的。

  • RegNtPreCreateKey 创建注册表之前
  • RegNtPreOpenKey 打开注册表之前
  • RegNtPreDeleteKey 删除注册表之前
  • RegNtPreDeleteValueKey 删除键值之前
  • RegNtPreSetValueKey 修改注册表之前

如果需要实现监视则,首先CmRegisterCallback注册一个自定义回调,当有消息时则触发MyLySharkCallback其内部获取到lOperateType操作类型,并通过switch选择不同的处理例程,每个处理例程都通过GetFullPath得到注册表完整路径,并打印出来,这段代码实现如下。

#include <ntifs.h>
#include <windef.h>// 未导出函数声明 pEProcess -> PID
PUCHAR PsGetProcessImageFileName(PEPROCESS pEProcess);NTSTATUS ObQueryNameString(_In_ PVOID Object,_Out_writes_bytes_opt_(Length) POBJECT_NAME_INFORMATION ObjectNameInfo,_In_ ULONG Length,_Out_ PULONG ReturnLength);// 注册表回调Cookie
LARGE_INTEGER g_liRegCookie;// 获取注册表完整路径
BOOLEAN GetFullPath(PUNICODE_STRING pRegistryPath, PVOID pRegistryObject)
{// 判断数据地址是否有效if ((FALSE == MmIsAddressValid(pRegistryObject)) ||(NULL == pRegistryObject)){return FALSE;}// 申请内存ULONG ulSize = 512;PVOID lpObjectNameInfo = ExAllocatePool(NonPagedPool, ulSize);if (NULL == lpObjectNameInfo){return FALSE;}// 获取注册表路径ULONG ulRetLen = 0;NTSTATUS status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)lpObjectNameInfo, ulSize, &ulRetLen);if (!NT_SUCCESS(status)){ExFreePool(lpObjectNameInfo);return FALSE;}// 复制RtlCopyUnicodeString(pRegistryPath, (PUNICODE_STRING)lpObjectNameInfo);// 释放内存ExFreePool(lpObjectNameInfo);return TRUE;
}// 注册表回调函数
NTSTATUS MyLySharkCallback(_In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2)
{NTSTATUS status = STATUS_SUCCESS;UNICODE_STRING ustrRegPath;// 获取操作类型LONG lOperateType = (REG_NOTIFY_CLASS)Argument1;// 申请内存ustrRegPath.Length = 0;ustrRegPath.MaximumLength = 1024 * sizeof(WCHAR);ustrRegPath.Buffer = ExAllocatePool(NonPagedPool, ustrRegPath.MaximumLength);if (NULL == ustrRegPath.Buffer){return status;}RtlZeroMemory(ustrRegPath.Buffer, ustrRegPath.MaximumLength);// 判断操作switch (lOperateType){// 创建注册表之前case RegNtPreCreateKey:{// 获取注册表路径GetFullPath(&ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->RootObject);DbgPrint("[创建注册表][%wZ][%wZ]\n", &ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->CompleteName);break;}// 打开注册表之前case RegNtPreOpenKey:{// 获取注册表路径GetFullPath(&ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->RootObject);DbgPrint("[打开注册表][%wZ][%wZ]\n", &ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->CompleteName);break;}// 删除键之前case RegNtPreDeleteKey:{// 获取注册表路径GetFullPath(&ustrRegPath, ((PREG_DELETE_KEY_INFORMATION)Argument2)->Object);DbgPrint("[删除键][%wZ] \n", &ustrRegPath);break;}// 删除键值之前case RegNtPreDeleteValueKey:{// 获取注册表路径GetFullPath(&ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->Object);DbgPrint("[删除键值][%wZ][%wZ] \n", &ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->ValueName);// 获取当前进程, 即操作注册表的进程PEPROCESS pEProcess = PsGetCurrentProcess();if (NULL != pEProcess){UCHAR *lpszProcessName = PsGetProcessImageFileName(pEProcess);if (NULL != lpszProcessName){DbgPrint("进程 [%s] 删除了键值对 \n", lpszProcessName);}}break;}// 修改键值之前case RegNtPreSetValueKey:{// 获取注册表路径GetFullPath(&ustrRegPath, ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)->Object);DbgPrint("[修改键值][%wZ][%wZ] \n", &ustrRegPath, ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)->ValueName);break;}default:break;}// 释放内存if (NULL != ustrRegPath.Buffer){ExFreePool(ustrRegPath.Buffer);ustrRegPath.Buffer = NULL;}return status;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));// 注销当前注册表回调if (0 < g_liRegCookie.QuadPart){CmUnRegisterCallback(g_liRegCookie);}
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint(("hello lyshark \n"));// 设置注册表回调NTSTATUS status = CmRegisterCallback(MyLySharkCallback, NULL, &g_liRegCookie);if (!NT_SUCCESS(status)){g_liRegCookie.QuadPart = 0;return status;}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

运行驱动程序,则会输出当前系统中所有针对注册表的操作,如下图所示。

如上的代码只能实现注册表项的监视,而如果需要监控则需要在回调函数MyLySharkCallback判断,如果指定注册表项是需要保护的则直接返回status = STATUS_ACCESS_DENIED;从而达到保护注册表的目的,核心代码如下所示。

// 反注册表删除回调
NTSTATUS MyLySharkCallback(_In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2)
{NTSTATUS status = STATUS_SUCCESS;UNICODE_STRING ustrRegPath;// 获取操作类型LONG lOperateType = (REG_NOTIFY_CLASS)Argument1;ustrRegPath.Length = 0;ustrRegPath.MaximumLength = 1024 * sizeof(WCHAR);ustrRegPath.Buffer = ExAllocatePool(NonPagedPool, ustrRegPath.MaximumLength);if (NULL == ustrRegPath.Buffer){return status;}RtlZeroMemory(ustrRegPath.Buffer, ustrRegPath.MaximumLength);// 判断操作switch (lOperateType){// 删除键值之前case RegNtPreDeleteValueKey:{// 获取注册表路径GetFullPath(&ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->Object);DbgPrint("[删除键值][%wZ][%wZ]\n", &ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->ValueName);// 如果要删除指定注册表项则拒绝PWCH pszRegister = L"\\REGISTRY\\MACHINE\\SOFTWARE\\lyshark";if (wcscmp(ustrRegPath.Buffer, pszRegister) == 0){DbgPrint("[lyshark] 注册表项删除操作已被拦截! \n");// 拒绝操作status = STATUS_ACCESS_DENIED;}break;}default:break;}// 释放内存if (NULL != ustrRegPath.Buffer){ExFreePool(ustrRegPath.Buffer);ustrRegPath.Buffer = NULL;}return status;
}

运行驱动程序,然后我们尝试删除\\LyShark\HKEY_LOCAL_MACHINE\SOFTWARE\lyshark里面的子项,则会提示如下信息。

当然这里的RegNtPreDeleteValueKey是指的删除操作,如果将其替换成RegNtPreSetValueKey,那么只有当注册表被创建才会拦截,此时就会变成拦截创建。

// 拦截创建操作
NTSTATUS MyLySharkCallback(_In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2)
{NTSTATUS status = STATUS_SUCCESS;UNICODE_STRING ustrRegPath;// 获取操作类型LONG lOperateType = (REG_NOTIFY_CLASS)Argument1;// 申请内存ustrRegPath.Length = 0;ustrRegPath.MaximumLength = 1024 * sizeof(WCHAR);ustrRegPath.Buffer = ExAllocatePool(NonPagedPool, ustrRegPath.MaximumLength);if (NULL == ustrRegPath.Buffer){return status;}RtlZeroMemory(ustrRegPath.Buffer, ustrRegPath.MaximumLength);// 判断操作switch (lOperateType){// 修改键值之前case RegNtPreSetValueKey:{// 获取注册表路径GetFullPath(&ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->Object);// 拦截创建PWCH pszRegister = L"\\REGISTRY\\MACHINE\\SOFTWARE\\lyshark";if (wcscmp(ustrRegPath.Buffer, pszRegister) == 0){DbgPrint("[lyshark] 注册表项创建操作已被拦截! \n");status = STATUS_ACCESS_DENIED;}break;}default:break;}// 释放内存if (NULL != ustrRegPath.Buffer){ExFreePool(ustrRegPath.Buffer);ustrRegPath.Buffer = NULL;}return status;
}

加载驱动保护,然后我们尝试在\\LyShark\HKEY_LOCAL_MACHINE\SOFTWARE\lyshark里面创建一个子项,则会提示创建失败。

相关文章:

7.5 Windows驱动开发:监控Register注册表回调

在笔者前一篇文章《内核枚举Registry注册表回调》中实现了对注册表的枚举&#xff0c;本章将实现对注册表的监控&#xff0c;不同于32位系统在64位系统中&#xff0c;微软为我们提供了两个针对注册表的专用内核监控函数&#xff0c;通过这两个函数可以在不劫持内核API的前提下实…...

NC56 XML 报文校验出错一例

好好的上线了、下午开完会告诉我有个凭证没法传入 NC 了。 请求报文如下&#xff1a; <?xml version"1.0" encodingUTF-8?> <ufinterface roottag"voucher" billtype"gl" replace"Y" receiver"10108" sender&q…...

STM32 ADC转换器、串口输出

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、ADC是什么&#xff1f;二、STM32的ADC2.1 认识STM32 ADC2.2转换方式2.3 为什么要校准&#xff1f;2.4 采样时间计算2.5 触发方式2.6 多通道采集解决方案2.7…...

[MySQL--基础]函数、约束

hello! 这里是欧_aita的频道。 今日语录:不管你觉得自己能做什么&#xff0c;或者你觉得你不能做什么&#xff0c;你都是对的。 祝福语&#xff1a;愿你的程序像太阳一样明亮&#xff0c;给世界带来温暖和光明。 大家可以在评论区畅所欲言&#xff0c;可以指出我的错误&#xf…...

企业数字化决策者深度分享

2023年11月18日&#xff0c;数聚股份应邀参加在台州椒江举办的数字中国企业峰会。本次会议中&#xff0c;诸多在企业数字化进程中做出重要贡献的高层管理者分享了各行各业极具引领性、创新性的数字化实践案例、产品和解决方案&#xff1b;数聚股份董事长陈庆华携其前瞻的数字化…...

JMeter压测常见面试问题

1、JMeter可以模拟哪些类型的负载&#xff1f; JMeter可以模拟各种类型的负载&#xff0c;包括但不限于Web应用程序、API、数据库、FTP、SMTP、JMS、SOAP / RESTful Web服务等。这使得JMeter成为一个功能强大且灵活的压力测试工具。 2、如何配置JMeter来进行分布式压力测试&a…...

使用opencv将sRGB格式的图片转换为DCI-P3格式【sRGB】【DCI-P3】

要将图像从 sRGB 格式转换为 DCI-P3 格式&#xff0c;您需要使用适当的线性转换矩阵。在 OpenCV 中&#xff0c;这通常涉及使用色彩转换函数&#xff0c;但 OpenCV 默认情况下不直接支持 sRGB 到 DCI-P3 的转换。因此&#xff0c;您需要手动计算并应用转换矩阵。 转换矩阵取决…...

【协议设计与实现】Linux环境下,如何从0开始设计并实现一个网络协议之一——需要考虑的因素

&#x1f41a;作者简介&#xff1a;花神庙码农&#xff08;专注于Linux、WLAN、TCP/IP、Python等技术方向&#xff09;&#x1f433;博客主页&#xff1a;花神庙码农 &#xff0c;地址&#xff1a;https://blog.csdn.net/qxhgd&#x1f310;系列专栏&#xff1a;TCP/IP协议&…...

【前端】JS实现SQL格式化

sqlFormatter sql-formatter - npm (npmjs.com) const sqlFormatter require(/utils/sqlFormatter)let sql select count(1) as cnt from t_user where id < 7;// 格式化 // let sqlF sqlFormatter.format(sql);let sqlF sqlFormatter.format(sql, {language:mysql,})…...

java设计模式学习之【工厂模式】

文章目录 引言工厂方法模式简介定义与用途&#xff1a;实现方式&#xff1a; 使用场景优势与劣势工厂模式在spring中的应用电费计算示例&#xff08;简单工厂模式&#xff09;改善为方法工厂模式代码地址 引言 在软件开发的世界中&#xff0c;对象的创建可能是一个复杂且重复的…...

android 内存分析(待续)

/proc/meminfo memory状态解读 命令&#xff1a;adb shell cat /proc/meminfo内存分布log 查看方式 命令&#xff1a;adb shell cat /proc/meminfo 用途:可以整体的了解memory使用情况 我们说的可用memory一般以MemAvailable的数据为准。所以了解MemAvailable的组成可以帮助…...

2023-简单点-机器学习中的数值计算问题

上溢和下溢&#xff1a; 上溢&#xff1a;指数函数或对数函数的输入值过大&#xff0c;导致计算结果超出了计算机可以表示的最大值。例如&#xff0c;在softmax函数中&#xff0c;当输入的数值很大时&#xff0c;指数运算的结果可能非常大&#xff0c;导致上溢。 下溢&#x…...

Qt5的事件处理函数有哪些?

2023年11月29日&#xff0c;周三上午 通过查看QWidget的定义可知&#xff0c;事件处理函数有&#xff1a; bool event(QEvent *event) override;virtual void mousePressEvent(QMouseEvent *event);virtual void mouseReleaseEvent(QMouseEvent *event);virtual void mouseDou…...

Jmeter性能综合实战——签到及批量签到

提取性能测试的三个方面&#xff1a;核心、高频、基础功能 签 到 请 求 步 骤 1、准备工作&#xff1a; 签到线程组 n HTTP请求默认值 n HTTP cookie 管理器 n 首页访问请求 n 登录请求 n 查看结果树 n 调试取样器 l HTTP代理服务器 &#xff08;1&#xff09;创建线…...

04 # 第一个 TypeScript 程序

初始化项目以及安装依赖 新建 ts_in_action 文件夾 npm init -y安装好 typescript&#xff0c;就可以执行下面命令查看帮助信息 npm i typescript -g tsc -h创建配置文件&#xff0c;执行下面命令就会生成一个 tsconfig.json 文件 tsc --init使用 tsc 编译一个 js 文件 新…...

Android gradle 配置阿里镜像

要在Android Gradle中配置阿里镜像&#xff0c;可以按照以下步骤进行操作&#xff1a; 打开项目中的 build.gradle 文件。 在 build.gradle 文件中添加阿里镜像的地址&#xff0c;如下所示&#xff1a; buildscript {repositories {maven { url https://maven.aliyun.com/re…...

Arduino驱动DHT20温湿度传感器(温湿度传感器)

目录 1、传感器特性 2、硬件原理图 3、控制器和传感器连线图 4、驱动程序 DHT20温湿度传感器是DHT11的全新升级版。 DHT20采用全新的ASIC专用芯片、改进的MEMS半导体电容式湿度传感器元件和标准片上温度元件。所有传感器均经过工厂校准,具有低功耗、高精度和稳定性、响应…...

如何使用ArcGIS Pro制作一张北极俯视地图

地图的表现形式有很多种&#xff0c;经常我们看到的地图是以大西洋为中心的地图&#xff0c;还有以太平洋为中心的地图&#xff0c;今天要给大家介绍的地图是从北极上方俯视看的地图&#xff0c;这里给大家讲解一下制作方法&#xff0c;希望能对你有所帮助。 修改坐标系 制作…...

每天五分钟计算机视觉:经典架构的力量与启示

在深度学习和计算机视觉领域,卷积神经网络(Convolutional Neural Networks,简称CNN)无疑是最为经典的架构之一。近年来,随着研究的不断深入和新架构的不断涌现,许多初学者可能会忽视这些经典架构的重要性。然而,理解并学习这些经典架构,对于我们深入理解卷积神经网络的…...

element plus 使用细节

菜鸟一直在纠结这个写不写&#xff0c;因为不难&#xff0c;但是菜鸟老是容易忘记&#xff0c;虽然想想或者搜搜就可以马上写出来&#xff0c;但是感觉每次那样就太麻烦了&#xff0c;不如一股做气写了算了&#xff0c;后面遇见别的就再来补充&#xff01; 文章目录 table 表格…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...