对象回调初步研究
_OBJECT_TYPE结构分析
在介绍什么是对象回调前,首先要熟悉下结构
以我们上篇线程回调介绍过的导出的PsProcessType 结构为例,用_OBJECT_TYPE这个结构来解析它,0x80处就是今天要介绍的回调链表,但是先不着急,先把目光聚焦到0x28这个TypeInfo结构上
1: kd> dd PsProcessType
83f7a02c 86ae5e38 86ae5f00 86ae5ca8 86ae5be0
83f7a03c 86ae58a8 83f45640 8fe87988 00010000
83f7a04c 00000cd8 00000258 00000000 00000001
83f7a05c 00000000 0000004b 00000001 00989680
83f7a06c 00000000 00000029 00000002 c0ffffff
83f7a07c c0607ff8 00000000 00000000 c0403080
83f7a08c 00000000 00010100 00000500 00000000
83f7a09c 00000001 00000000 0000000d 00040107
1: kd> dt _OBJECT_TYPE 86ae5e38
ntdll!_OBJECT_TYPE+0x000 TypeList : _LIST_ENTRY [ 0x86ae5e38 - 0x86ae5e38 ]+0x008 Name : _UNICODE_STRING "Process"+0x010 DefaultObject : (null) +0x014 Index : 0x7 ''+0x018 TotalNumberOfObjects : 0x21+0x01c TotalNumberOfHandles : 0xc1+0x020 HighWaterNumberOfObjects : 0x2a+0x024 HighWaterNumberOfHandles : 0xe3+0x028 TypeInfo : _OBJECT_TYPE_INITIALIZER//+0x078 TypeLock : _EX_PUSH_LOCK+0x07c Key : 0x636f7250+0x080 CallbackList : _LIST_ENTRY [ 0x86ae5eb8 - 0x86ae5eb8 ]//
这个TypeInfo里面也存着一部分值得关注的信息,从0x30开始的回调函数的调用会优先于我们将要介绍的对象回调,比如0x34的这个回调就是在OpenProcess执行之后先被执行,然后其中会进行一系列处理(比如之前也介绍过的通过进程id打开进程对象)
1: kd> dt _OBJECT_TYPE_INITIALIZER 86ae5e38+0x28
ntdll!_OBJECT_TYPE_INITIALIZER+0x000 Length : 0x50+0x002 ObjectTypeFlags : 0x4a 'J'+0x002 CaseInsensitive : 0y0+0x002 UnnamedObjectsOnly : 0y1+0x002 UseDefaultObject : 0y0+0x002 SecurityRequired : 0y1+0x002 MaintainHandleCount : 0y0+0x002 MaintainTypeList : 0y0+0x002 SupportsObjectCallbacks : 0y1//是否支持回调标志位,如果修改会被PG+0x004 ObjectTypeCode : 0+0x008 InvalidAttributes : 0xb0+0x00c GenericMapping : _GENERIC_MAPPING+0x01c ValidAccessMask : 0x1fffff//权限掩码+0x020 RetainAccess : 0x101000+0x024 PoolType : 0 ( NonPagedPool )+0x028 DefaultPagedPoolCharge : 0x1000+0x02c DefaultNonPagedPoolCharge : 0x2f0+0x030 DumpProcedure : (null) +0x034 OpenProcedure : 0x84021ccb long nt!PspProcessOpen+0//win官方注册的回调+0x038 CloseProcedure : 0x84081d2e void nt!PspProcessClose+0+0x03c DeleteProcedure : 0x840845f5 void nt!PspProcessDelete+0+0x040 ParseProcedure : (null) +0x044 SecurityProcedure : 0x840765b6 long nt!SeDefaultObjectMethod+0+0x048 QueryNameProcedure : (null) +0x04c OkayToCloseProcedure : (null)
可以用pchunter看这些钩子,他们都是挂在内核里面的
这些对象的作用是全局性的,那么可以怎么用呢
DebugObject使用示例
在内核中的DbgkpInitializePhase0这个函数里面,有DbgObject的定义,这说明官方的符号表里面有这个对象
我们在Windbg中来看这个对象(DbgkDebugObjectType),
1: kd> dd DbgkDebugObjectType
83f48dac 86ae5528 00000000 8d86a330 00000003
83f48dbc 00000012 0000002a 000000a1 00000024
83f48dcc 8caa5b3c 01010000 00000002 8322ee0d
83f48ddc 83ee1508 00000000 00000000 00000000
83f48dec 00000003 83e10550 87dbb030 00000000
83f48dfc 00000000 00000000 00000000 00000003
83f48e0c 00000001 00000001 00000001 00000001
83f48e1c 83212408 83212006 8320c006 832122fa
1: kd> dt _OBJECT_TYPE 86ae5528
nt!_OBJECT_TYPE+0x000 TypeList : _LIST_ENTRY [ 0x86ae5528 - 0x86ae5528 ]+0x008 Name : _UNICODE_STRING "DebugObject"//对象名字+0x010 DefaultObject : (null) +0x014 Index : 0xb ''+0x018 TotalNumberOfObjects : 0+0x01c TotalNumberOfHandles : 0+0x020 HighWaterNumberOfObjects : 0+0x024 HighWaterNumberOfHandles : 0+0x028 TypeInfo : _OBJECT_TYPE_INITIALIZER+0x078 TypeLock : _EX_PUSH_LOCK+0x07c Key : 0x75626544+0x080 CallbackList : _LIST_ENTRY [ 0x86ae55a8 - 0x86ae55a8 ]
同理,也来看看它的TypeInfo
1: kd> dt _OBJECT_TYPE_INITIALIZER 86ae5528+0x28
nt!_OBJECT_TYPE_INITIALIZER+0x000 Length : 0x50+0x002 ObjectTypeFlags : 0x8 ''+0x002 CaseInsensitive : 0y0+0x002 UnnamedObjectsOnly : 0y0+0x002 UseDefaultObject : 0y0+0x002 SecurityRequired : 0y1+0x002 MaintainHandleCount : 0y0+0x002 MaintainTypeList : 0y0+0x002 SupportsObjectCallbacks : 0y0+0x004 ObjectTypeCode : 0+0x008 InvalidAttributes : 0+0x00c GenericMapping : _GENERIC_MAPPING+0x01c ValidAccessMask : 0x1f000f//这是这个对象的权限掩码+0x020 RetainAccess : 0+0x024 PoolType : 0 ( NonPagedPool )+0x028 DefaultPagedPoolCharge : 0+0x02c DefaultNonPagedPoolCharge : 0x30+0x030 DumpProcedure : (null) +0x034 OpenProcedure : (null) +0x038 CloseProcedure : 0x840be98b void nt!DbgkpCloseObject+0+0x03c DeleteProcedure : 0x8408e87e void nt!ExpDeleteCallback+0+0x040 ParseProcedure : (null) +0x044 SecurityProcedure : 0x840765b6 long nt!SeDefaultObjectMethod+0+0x048 QueryNameProcedure : (null) +0x04c OkayToCloseProcedure : (null)
如果我们将它的ValidAccessMask置零,那么其他进程申请调试时就无法正确创建调试对象,从而达到简单反调试的作用,当然,这样做非常暴力。
1: kd> ed 86ae5528+0x28+1c 0
WriteVirtual: 86ae556c not properly sign extended
1: kd> dt _OBJECT_TYPE_INITIALIZER 86ae5528+0x28
nt!_OBJECT_TYPE_INITIALIZER+0x000 Length : 0x50+0x002 ObjectTypeFlags : 0x8 ''+0x002 CaseInsensitive : 0y0+0x002 UnnamedObjectsOnly : 0y0+0x002 UseDefaultObject : 0y0+0x002 SecurityRequired : 0y1+0x002 MaintainHandleCount : 0y0+0x002 MaintainTypeList : 0y0+0x002 SupportsObjectCallbacks : 0y0+0x004 ObjectTypeCode : 0+0x008 InvalidAttributes : 0+0x00c GenericMapping : _GENERIC_MAPPING+0x01c ValidAccessMask : 0+0x020 RetainAccess : 0+0x024 PoolType : 0 ( NonPagedPool )+0x028 DefaultPagedPoolCharge : 0+0x02c DefaultNonPagedPoolCharge : 0x30+0x030 DumpProcedure : (null) +0x034 OpenProcedure : (null) +0x038 CloseProcedure : 0x840be98b void nt!DbgkpCloseObject+0+0x03c DeleteProcedure : 0x8408e87e void nt!ExpDeleteCallback+0+0x040 ParseProcedure : (null) +0x044 SecurityProcedure : 0x840765b6 long nt!SeDefaultObjectMethod+0+0x048 QueryNameProcedure : (null) +0x04c OkayToCloseProcedure : (null)
这时候我们来看看电脑上的调试功能,比如CE
然后就是Dbgview,图有点看不清,但是意思就是调试没开始就结束了
我们在手动修改的层面上去实践了这种做法,这样我们就可以更好的理解了待会要做的事情。
注册我们的对象回调
在win中,注册对象我们一般使用ObRegisterCallbacks
先来看看这个函数的参数,参数有两个一个是CallbackRegistration,这是一个记录我们回调信息的结构;第二个参数是RegistrationHandle,这是一个用来接收我们用来标识注册回调例程的值
NTSTATUS ObRegisterCallbacks([in] POB_CALLBACK_REGISTRATION CallbackRegistration,[out] PVOID *RegistrationHandle
);
[in] CallbackRegistration
指向 OB_CALLBACK_REGISTRATION 结构的指针,该结构指定回调例程和其他注册信息的列表。[out] RegistrationHandle
指向变量的指针,该变量接收标识注册的回调例程集的值。 调用方将此值传递给 ObUnRegisterCallbacks 例程,以取消注册回调集。
首先要了解这个POB_CALLBACK_REGISTRATION的结构,所以我们知道,我们在这个结构中要填四个值
typedef struct _OB_CALLBACK_REGISTRATION {USHORT Version;USHORT OperationRegistrationCount;UNICODE_STRING Altitude;PVOID RegistrationContext;OB_OPERATION_REGISTRATION *OperationRegistration;
} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;
Version
请求的对象回调注册的版本。 驱动程序应指定OB_FLT_REGISTRATION_VERSION。OperationRegistrationCount
OperationRegistration 数组中的条目数。Altitude
一个 Unicode 字符串,指定驱动程序的高度。 有关海拔的详细信息,请参阅 微型筛选器驱动程序的加载顺序组和高度。RegistrationContext
运行回调例程时,系统将 RegistrationContext 值传递给回调例程。 此值的含义是驱动程序定义的。OperationRegistration
指向 OB_OPERATION_REGISTRATION 结构的数组的指针。 每个结构指定 ObjectPreCallback 和 ObjectPostCallback 回调例程以及调用例程的作类型。
第一个参数就是Version,这里建议我们使用OB_FLT_REGISTRATION_VERSION这个宏来获取版本号
它其实就是这么一个值
#define OB_FLT_REGISTRATION_VERSION_0100 0x0100
这里我们建议使用ObGetFilterVersion这个函数,可以看见返回的值是一样的,但是用函数有一个好处,不管什么版本的内核,都会返回正确的版本,不会因为环境的改变而受影响。
第二个参数是OperationRegistrationCount,也就是下面第五个参数OperationRegistration是一个回调函数数组,第二个参数的意义就是说明这个数组里面有多少个回调
第三个参数被称为Altitude,它是海拔,现在先简单理解,这里说的“指定驱动程序的高度”,其实应该是驱动的优先级。这个东西比较复杂这里先不详细介绍。
这里稍微说明一下,不是必须要规定在这些海拔范围内才能生效,这些海拔本身只是一个参考值
第四个参数是RegistrationContext,这是我们传给回调例程的参数
第五个参数就是OperationRegistration,这也有一个结构OB_OPERATION_REGISTRATION,看看这个结构的样子,要填的包括例子官方已经给过了,需要注意的是PreOperation和PostOperation,这分别是我们前回调和后回调。
比如,我Operations填了OB_OPERATION_HANDLE_CREATE,那么就会在我创建这个对象前执行PreOperation,创建后执行PostOperation,这两个回调可以只填一个,但是不能两个都不填
typedef struct _OB_OPERATION_REGISTRATION {POBJECT_TYPE *ObjectType;OB_OPERATION Operations;POB_PRE_OPERATION_CALLBACK PreOperation;POB_POST_OPERATION_CALLBACK PostOperation;
} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;
ObjectType
指向触发回调例程的对象类型的指针。 指定以下值之一:
处理作的 PsProcessType
线程句柄作的 PsThreadType
ExDesktopObjectType 桌面句柄作。 此值在 Windows 10 中不受早期版本的作系统支持。Operations
指定以下一个或多个标志:
OB_OPERATION_HANDLE_CREATE
新进程、线程或桌面句柄已打开或将打开。
OB_OPERATION_HANDLE_DUPLICATE
进程、线程或桌面句柄是或将被复制。PreOperation
指向 ObjectPreCallback 例程的指针。 系统在请求的作发生之前调用此例程。PostOperation
指向 ObjectPostCallback 例程的指针。 系统在请求的作发生后调用此例程。
关于这两个回调的结构,我同样给出。
typedef OB_PREOP_CALLBACK_STATUS
(*POB_PRE_OPERATION_CALLBACK) (_In_ PVOID RegistrationContext,_Inout_ POB_PRE_OPERATION_INFORMATION OperationInformation);typedef VOID
(*POB_POST_OPERATION_CALLBACK) (_In_ PVOID RegistrationContext,_In_ POB_POST_OPERATION_INFORMATION OperationInformation);
以及回调中的POB_POST_OPERATION_INFORMATION
typedef struct _OB_PRE_OPERATION_INFORMATION {_In_ OB_OPERATION Operation;union {_In_ ULONG Flags;struct {_In_ ULONG KernelHandle:1;_In_ ULONG Reserved:31;};};_In_ PVOID Object;_In_ POBJECT_TYPE ObjectType;_Out_ PVOID CallContext;_In_ POB_PRE_OPERATION_PARAMETERS Parameters;
} OB_PRE_OPERATION_INFORMATION, *POB_PRE_OPERATION_INFORMATION;
现在我们所有的材料已经备齐了,可以来写一些demo
我们知道,任务管理器里面结束进程也是通过R3的API,它也是调用类似TerminateProcess这样的API对进程进行终结,让我们来回顾一下这个函数的参数,可以看见,我们就需要向其中传入句柄,传入句柄,也就是需要打开句柄OpenProcess。
BOOL TerminateProcess([in] HANDLE hProcess,[in] UINT uExitCode
);
所以,我们能不能用注册一个对象回调,让进程对象在被申请的时候检查,如果是我们的程序,就清空当前进程权限位,使其无法打开我们的程序。
demo
#include<ntifs.h>//0x78 bytes (sizeof)
typedef struct _LDR_DATA_TABLE_ENTRY
{LIST_ENTRY InLoadOrderLinks; //0x0LIST_ENTRY InMemoryOrderLinks; //0x8LIST_ENTRY InInitializationOrderLinks; //0x10VOID* DllBase; //0x18VOID* EntryPoint; //0x1cULONG SizeOfImage; //0x20UNICODE_STRING FullDllName; //0x24UNICODE_STRING BaseDllName; //0x2cULONG Flags; //0x34可以不要之后的内容
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;PVOID RegistrationHandle = NULL;EXTERN_C PUCHAR NTAPI PsGetProcessImageFileName(PEPROCESS Process);//前回调
OB_PREOP_CALLBACK_STATUS PreCallBack(_In_ PVOID RegistrationContext,_Inout_ POB_PRE_OPERATION_INFORMATION OperationInformation){//获取当前进程PEPROCESS CurProcess = IoGetCurrentProcess();//获取被操作的进程PEPROCESS TargetProcess = (PEPROCESS)OperationInformation->Object;//获取当前进程名字PUCHAR CurName = PsGetProcessImageFileName(CurProcess);//获取目标进程名字PUCHAR TargetName = PsGetProcessImageFileName(TargetProcess);//获取当前操作PUCHAR CurOperation = OperationInformation->Operation;//获取FlagsULONG KernelMode = OperationInformation->Flags&0x1;PUCHAR CurOperationName = NULL;if (CurOperation == 0x1) {CurOperationName = "Create";DbgPrint("[+] CurrentName is %s,TargeName is %s,Operation is %s in ring%d\n", CurName, TargetName, CurOperationName, KernelMode * 3);}else if(CurOperation == 0x10) {CurOperationName = "Duplicate";}else {CurOperationName = "Create and Duplicate";}if (strstr("my.exe", TargetName)) {OperationInformation->Parameters->CreateHandleInformation.DesiredAccess = 0;}return OB_PREOP_SUCCESS;
}
//后回调
VOID PostCallBack(_In_ PVOID RegistrationContext,_In_ POB_POST_OPERATION_INFORMATION OperationInformation
) {}VOID DriverUnload(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {DbgBreakPoint();if (RegistrationHandle) {ObUnRegisterCallbacks(RegistrationHandle);}
}NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {//初始化回调信息结构OB_CALLBACK_REGISTRATION obRegInfo = { 0 };obRegInfo.Version = ObGetFilterVersion();obRegInfo.OperationRegistrationCount = 1;obRegInfo.RegistrationContext = NULL;RtlInitUnicodeString(&obRegInfo.Altitude, L"123456");//回调函数结构OB_OPERATION_REGISTRATION obCallBcakInfo = { 0 };obCallBcakInfo.ObjectType = *PsProcessType;//OpenProcess和DunmplicateHandle都回调obCallBcakInfo.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;obCallBcakInfo.PreOperation = PreCallBack;obCallBcakInfo.PostOperation = PostCallBack;PLDR_DATA_TABLE_ENTRY ex = (PLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;ex->Flags |= 0x20;//注册obRegInfo.OperationRegistration = &obCallBcakInfo;NTSTATUS state = ObRegisterCallbacks(&obRegInfo, &RegistrationHandle);DbgPrint("[+] The state is %x\n", state);if (NT_SUCCESS(state)) {}pDriver->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}
这里只略微提到两点:1.这类回调如果出现了C0x000022的问题,那么大概率是Flags有问题,Flags检查没过,具体的东西我之前的文章里面说过了
2.PreCallBack和PostCallBack里面一般拦截放在PreCallBack,也就是Create或Delicate对象前。
通过上述代码,我们就可以实现类似杀软那种别人用任务管理器关不掉的效果
为了方便测试,又用的CPU-z,改了下名字
程序启动之后,加载驱动
这里说一下发现,上了驱动之后,任务管理器一直在不间断的操作几个进程的对象
这时候我们尝试使用任务管理器结束进程,可以看见我们操作相关对象的时候就被拒绝了,这就达到了我们的目的。
最后的问题
这里有一个问题我没有解决,那就是在停止驱动的时候会蓝屏,0x00000039,在取消回调的时候回调句柄是被赋了值的,但是我一直没搞清楚为什么会蓝屏。中间还修改了DriverSection的Flags的值,把它改了回去,但是还是无济于事。
相关文章:

对象回调初步研究
_OBJECT_TYPE结构分析 在介绍什么是对象回调前,首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例,用_OBJECT_TYPE这个结构来解析它,0x80处就是今天要介绍的回调链表,但是先不着急,先把目光…...
TCP/IP 网络编程 | 服务端 客户端的封装
设计模式 文章目录 设计模式一、socket.h 接口(interface)二、socket.cpp 实现(implementation)三、server.cpp 使用封装(main 函数)四、client.cpp 使用封装(main 函数)五、退出方法…...
数据库——redis
一、Redis 介绍 1. 概述 Redis(Remote Dictionary Server)是一个开源的、高性能的内存键值数据库系统,具有以下核心特点: 内存存储架构:数据主要存储在内存中,提供微秒级的读写响应 多数据结构支持&…...

Java后端检查空条件查询
通过抛出运行异常:throw new RuntimeException("请输入查询条件!");BranchWarehouseServiceImpl.java // 查询试剂交易(入库/出库)记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...

PH热榜 | 2025-06-08
1. Thiings 标语:一套超过1900个免费AI生成的3D图标集合 介绍:Thiings是一个不断扩展的免费AI生成3D图标库,目前已有超过1900个图标。你可以按照主题浏览,生成自己的图标,或者下载整个图标集。所有图标都可以在个人或…...

C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...
JS红宝书笔记 - 3.3 变量
要定义变量,可以使用var操作符,后跟变量名 ES实现变量初始化,因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符,可以创建一个全局变量 如果需要定义…...
2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案
一、延迟敏感行业面临的DDoS攻击新挑战 2025年,金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征: AI驱动的自适应攻击:攻击流量模拟真实用户行为,差异率低至0.5%,传统规则引…...

聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇
根据 QYResearch 发布的市场报告显示,全球市场规模预计在 2031 年达到 9848 万美元,2025 - 2031 年期间年复合增长率(CAGR)为 3.7%。在竞争格局上,市场集中度较高,2024 年全球前十强厂商占据约 74.0% 的市场…...

【iOS】 Block再学习
iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...

Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...
文件上传漏洞防御全攻略
要全面防范文件上传漏洞,需构建多层防御体系,结合技术验证、存储隔离与权限控制: 🔒 一、基础防护层 前端校验(仅辅助) 通过JavaScript限制文件后缀名(白名单)和大小,提…...

STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
webpack面试题
面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...

何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...

【若依】框架项目部署笔记
参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作: 压缩包下载:http://download.redis.io/releases 1. 上传压缩包,并进入压缩包所在目录,解压到目标…...
深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙
WebGL:在浏览器中解锁3D世界的魔法钥匙 引言:网页的边界正在消失 在数字化浪潮的推动下,网页早已不再是静态信息的展示窗口。如今,我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室,甚至沉浸式的V…...

2025年- H71-Lc179--39.组合总和(回溯,组合)--Java版
1.题目描述 2.思路 当前的元素可以重复使用。 (1)确定回溯算法函数的参数和返回值(一般是void类型) (2)因为是用递归实现的,所以我们要确定终止条件 (3)单层搜索逻辑 二…...
数据库正常,但后端收不到数据原因及解决
从代码和日志来看,后端SQL查询确实返回了数据,但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离,并且ai辅助开发的时候,很容易出现前后端变量名不一致情况,还不报错,只是单…...

Java数组Arrays操作全攻略
Arrays类的概述 Java中的Arrays类位于java.util包中,提供了一系列静态方法用于操作数组(如排序、搜索、填充、比较等)。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序(sort) 对数组进行升序…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...
Python学习(8) ----- Python的类与对象
Python 中的类(Class)与对象(Object)是面向对象编程(OOP)的核心。我们可以通过“类是模板,对象是实例”来理解它们的关系。 🧱 一句话理解: 类就像“图纸”,对…...
ThreadLocal 源码
ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物,因为每个访问一个线程局部变量的线程(通过其 get 或 set 方法)都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段,这些类希望将…...
Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合
无论是python,或者java 的大型项目中,都会涉及到 自身平台微服务之间的相互调用,以及和第三发平台的 接口对接,那在python 中是怎么实现的呢? 在 Python Web 开发中,FastAPI 和 Django 是两个重要但定位不…...

rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架: 代码框架结构:readme有…...

高分辨率图像合成归一化流扩展
大家读完觉得有帮助记得关注和点赞!!! 1 摘要 我们提出了STARFlow,一种基于归一化流的可扩展生成模型,它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流(TARFlow&am…...

负载均衡器》》LVS、Nginx、HAproxy 区别
虚拟主机 先4,后7...
命令行关闭Windows防火墙
命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)方法二:CMD命令…...