7.1 Windows驱动开发:内核监控进程与线程回调
在前面的文章中LyShark
一直在重复的实现对系统底层模块的枚举,今天我们将展开一个新的话题,内核监控,我们以监控进程线程
创建为例,在Win10
系统中监控进程与线程可以使用微软提供给我们的两个新函数来实现,此类函数的原理是创建一个回调事件,当有进程或线程被创建或者注销时,系统会通过回调机制将该进程相关信息优先返回给我们自己的函数待处理结束后再转向系统层。
PsSetCreateProcessNotifyRoutineEx和PsSetCreateThreadNotifyRoutine是Windows操作系统提供的两个内核回调函数,它们允许开发者在进程或线程发生创建事件时拦截并处理这些事件。这两个函数提供的回调机制是操作系统提供的最基本、最常用的内核监控进程与线程的方式。
PsSetCreateProcessNotifyRoutineEx和PsSetCreateThreadNotifyRoutine的使用方式和参数类型类似,它们都需要开发者提供一个回调函数,当进程或线程被创建时,操作系统会调用这个回调函数。这个回调函数需要满足一定的约束条件,例如不能阻塞或挂起进程或线程的创建或访问,不能调用一些内核API函数等。
PsSetCreateProcessNotifyRoutineEx和PsSetCreateThreadNotifyRoutine的主要区别在于它们所监控的事件不同。PsSetCreateProcessNotifyRoutineEx用于监控进程的创建事件,当有新的进程被创建时,操作系统会调用注册的回调函数。而PsSetCreateThreadNotifyRoutine用于监控线程的创建事件,当有新的线程被创建时,操作系统会调用注册的回调函数。
内核监控进程PsSetCreateProcessNotifyRoutineEx和线程PsSetCreateThreadNotifyRoutine回调在安全软件、系统监控和调试工具等领域有着广泛的应用。需要注意的是,在Windows 8及更高版本的操作系统中,微软推荐开发者使用ExRegisterCallback和ExUnregisterCallback函数进行回调的注册和注销。
进程回调默认会设置CreateProcess
通知,而线程回调则会设置CreateThread
通知,我们来看ARK工具中的枚举效果。
- 通常情况下:
- PsSetCreateProcessNotifyRoutineEx 用于监控进程
- PsSetCreateThreadNotifyRoutine 用于监控线程
PsSetCreateProcessNotifyRoutineEx
监控进程的启动与退出可以使用 PsSetCreateProcessNotifyRoutineEx
来创建回调,当新进程创建时会优先执行回调,我们看下微软是如何定义的结构。
// 参数1: 新进程回调函数
// 参数2: 是否注销
NTSTATUS PsSetCreateProcessNotifyRoutineEx([in] PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine,[in] BOOLEAN Remove
);
如上,该函数只有两个参数,第一个参数是回调函数,第二个参数是是否注销,通常在驱动退出时可以传入TRUE
对该回调进行注销,通常情况下如果驱动关闭,则必须要注销回调,而对于MyLySharkCreateProcessNotifyEx
自定义回调来说,则需要指定三个必须要有的参数传递。
// 参数1: 新进程的EProcess
// 参数2: 新进程PID
// 参数3: 新进程详细信息 (仅在创建进程时有效)VOID MyLySharkCreateProcessNotifyEx(PEPROCESS Process, HANDLE ProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo)
根据如上函数定义,就可以实现监控功能了,例如我们监控如果进程名是lyshark.exe
则直接CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL
禁止该进程打开。
#include <ntifs.h>// 两个未公开函数导出
NTKERNELAPI PCHAR PsGetProcessImageFileName(PEPROCESS Process);
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);// 通过PID获得进程名
PCHAR GetProcessNameByProcessId(HANDLE ProcessId)
{NTSTATUS st = STATUS_UNSUCCESSFUL;PEPROCESS ProcessObj = NULL;PCHAR string = NULL;st = PsLookupProcessByProcessId(ProcessId, &ProcessObj);if (NT_SUCCESS(st)){string = PsGetProcessImageFileName(ProcessObj);ObfDereferenceObject(ProcessObj);}return string;
}// 绕过签名检查
BOOLEAN BypassCheckSign(PDRIVER_OBJECT pDriverObject)
{
#ifdef _WIN64typedef struct _KLDR_DATA_TABLE_ENTRY{LIST_ENTRY listEntry;ULONG64 __Undefined1;ULONG64 __Undefined2;ULONG64 __Undefined3;ULONG64 NonPagedDebugInfo;ULONG64 DllBase;ULONG64 EntryPoint;ULONG SizeOfImage;UNICODE_STRING path;UNICODE_STRING name;ULONG Flags;USHORT LoadCount;USHORT __Undefined5;ULONG64 __Undefined6;ULONG CheckSum;ULONG __padding1;ULONG TimeDateStamp;ULONG __padding2;} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
#elsetypedef struct _KLDR_DATA_TABLE_ENTRY{LIST_ENTRY listEntry;ULONG unknown1;ULONG unknown2;ULONG unknown3;ULONG unknown4;ULONG unknown5;ULONG unknown6;ULONG unknown7;UNICODE_STRING path;UNICODE_STRING name;ULONG Flags;} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
#endifPKLDR_DATA_TABLE_ENTRY pLdrData = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;pLdrData->Flags = pLdrData->Flags | 0x20;return TRUE;
}// 进程回调函数
VOID My_LyShark_Com_CreateProcessNotifyEx(PEPROCESS Process, HANDLE ProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo)
{char ProcName[16] = { 0 };if (CreateInfo != NULL){strcpy_s(ProcName, 16, PsGetProcessImageFileName(Process));DbgPrint("[LyShark] 父进程ID: %ld | 父进程名: %s | 进程名: %s | 进程路径:%wZ \n", CreateInfo->ParentProcessId, GetProcessNameByProcessId(CreateInfo->ParentProcessId), PsGetProcessImageFileName(Process), CreateInfo->ImageFileName);// 判断是否为指定进程if (0 == _stricmp(ProcName, "lyshark.exe")){// 禁止打开CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL;}}else{strcpy_s(ProcName, 16, PsGetProcessImageFileName(Process));DbgPrint("[LyShark] 进程[ %s ] 退出了, 程序被关闭", ProcName);}
}VOID UnDriver(PDRIVER_OBJECT driver)
{DWORD32 ref = 0;// 注销进程回调ref = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)My_LyShark_Com_CreateProcessNotifyEx, TRUE);DbgPrint("[lyshark] 注销进程回调: %d \n", ref);
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{NTSTATUS status;// 绕过签名检查// LINKER_FLAGS=/INTEGRITYCHECKBypassCheckSign(Driver);DbgPrint("hello lyshark \n");// 创建进程回调// 参数1: 新进程的EProcess// 参数2: 新进程PID// 参数3: 新进程详细信息 (仅在创建进程时有效)status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)My_LyShark_Com_CreateProcessNotifyEx, FALSE);if (!NT_SUCCESS(status)){DbgPrint("[lyshark] 创建进程回调错误");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}
编译并运行这个驱动程序,我们可以在ARK
工具中看到这个驱动所加载的CreateProcess
的回调事件。
当驱动加载后,如果你尝试打开lyshark.exe
那么会提示连接的设备没有发挥作用,我们则成功拦截了这次打开,当然如果在打开进程之前扫描其特征并根据特征拒绝进程打开,那么就可以实现一个简单的防恶意程序,进程监控在防恶意程序中也是用的最多的。
PsSetCreateThreadNotifyRoutine
说完了PsSetCreateProcessNotifyRoutineEx
回调的使用方式,LyShark将继续带大家看看线程监控
如何实现,监控线程创建与监控进程差不多,检测线程需要调用PsSetCreateThreadNotifyRoutine
创建回调函数,之后就可监控系统所有线程的创建,具体实现代码如下。
#include <ntifs.h>// 两个未公开函数导出
NTKERNELAPI PCHAR PsGetProcessImageFileName(PEPROCESS Process);
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
NTKERNELAPI NTSTATUS PsLookupThreadByThreadId(HANDLE ThreadId, PETHREAD *Thread);// 绕过签名检查
BOOLEAN BypassCheckSign(PDRIVER_OBJECT pDriverObject)
{
#ifdef _WIN64typedef struct _KLDR_DATA_TABLE_ENTRY{LIST_ENTRY listEntry;ULONG64 __Undefined1;ULONG64 __Undefined2;ULONG64 __Undefined3;ULONG64 NonPagedDebugInfo;ULONG64 DllBase;ULONG64 EntryPoint;ULONG SizeOfImage;UNICODE_STRING path;UNICODE_STRING name;ULONG Flags;USHORT LoadCount;USHORT __Undefined5;ULONG64 __Undefined6;ULONG CheckSum;ULONG __padding1;ULONG TimeDateStamp;ULONG __padding2;} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
#elsetypedef struct _KLDR_DATA_TABLE_ENTRY{LIST_ENTRY listEntry;ULONG unknown1;ULONG unknown2;ULONG unknown3;ULONG unknown4;ULONG unknown5;ULONG unknown6;ULONG unknown7;UNICODE_STRING path;UNICODE_STRING name;ULONG Flags;} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
#endifPKLDR_DATA_TABLE_ENTRY pLdrData = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;pLdrData->Flags = pLdrData->Flags | 0x20;return TRUE;
}// 线程回调函数
VOID MyCreateThreadNotify(HANDLE ProcessId, HANDLE ThreadId, BOOLEAN CreateInfo)
{PEPROCESS eprocess = NULL;PETHREAD ethread = NULL;UCHAR *pWin32Address = NULL;// 通过此函数拿到程序的EPROCESS结构PsLookupProcessByProcessId(ProcessId, &eprocess);PsLookupThreadByThreadId(ThreadId, ðread);if (CreateInfo){DbgPrint("[lyshark] 线程TID: %1d | 所属进程名: %s | 进程PID: %1d \n", ThreadId, PsGetProcessImageFileName(eprocess), PsGetProcessId(eprocess));/*if (0 == _stricmp(PsGetProcessImageFileName(eprocess), "lyshark.exe")){DbgPrint("线程TID: %1d | 所属进程名: %s | 进程PID: %1d \n", ThreadId, PsGetProcessImageFileName(eprocess), PsGetProcessId(eprocess));// dt _kthread// 寻找里面的 Win32StartAddress 并写入retpWin32Address = *(UCHAR**)((UCHAR*)ethread + 0x1c8);if (MmIsAddressValid(pWin32Address)){*pWin32Address = 0xC3;}}*/}else{DbgPrint("[LyShark] %s 线程已退出...", ThreadId);}if (eprocess)ObDereferenceObject(eprocess);if (ethread)ObDereferenceObject(ethread);
}VOID UnDriver(PDRIVER_OBJECT driver)
{NTSTATUS status;// 注销进程回调status = PsRemoveCreateThreadNotifyRoutine(MyCreateThreadNotify);
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{NTSTATUS status;DbgPrint("hello lyshark \n");// 绕过签名检查// LINKER_FLAGS=/INTEGRITYCHECKBypassCheckSign(Driver);// 创建线程回调// 参数1: 新线程ProcessID// 参数2: 新线程ThreadID// 参数3: 线程创建/退出标志status = PsSetCreateThreadNotifyRoutine(MyCreateThreadNotify);if (!NT_SUCCESS(status)){DbgPrint("创建线程回调错误");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}
运行后则可监控到系统总所有线程的创建与退出,效果如下所示:
相关文章:

7.1 Windows驱动开发:内核监控进程与线程回调
在前面的文章中LyShark一直在重复的实现对系统底层模块的枚举,今天我们将展开一个新的话题,内核监控,我们以监控进程线程创建为例,在Win10系统中监控进程与线程可以使用微软提供给我们的两个新函数来实现,此类函数的原…...

基于ssm的汽车论坛管理系统设计与实现
基于ssm的汽车论坛管理系统设计与实现 摘要:信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题…...
实习开发日志经验总结(一)
文章目录 前言实习日志经验总结 前言 自己之前实习过程中遇到的问题以及相应的解决过程,我都有记录形成比较凌乱的实习日志。故想在整个实习日志的基础上,提炼一些技术知识点或者是解决问题的思路。考虑到实习项目的不方便公开性,所以会隐去…...

【Unity基础】8.简单场景的搭建
【Unity基础】8.简单场景的搭建 大家好,我是Lampard~~ 欢迎来到Unity基础系列博客,所学知识来自B站阿发老师~感谢 (一)场景资源 (1)Import资源包 今天我们将手动去搭一个简单的场景,当…...

傅里叶变换及其在机器学习中的应用
一、介绍 傅立叶变换是一种数学技术,在各个科学和工程领域发挥着关键作用,其应用范围从信号处理到量子力学。近年来,它在机器学习领域发现了新的意义。本文探讨了傅里叶变换的基础知识及其在机器学习应用中日益增长的重要性。 …...

xorm源码学习
文章目录 XORM源码浅析及实践ORMORM vs. SQLXORM软件架构 ORM 引擎 Engine——DBM*core.DB Golang:database/sql 源码基本结构连接复用,提高性能。增加数据库连接池数量连接管理 database/sql主要内容:sql.DB创建数据库连接sql.Open()DB.conn…...
Vue3中的<script setup>和<script>的区别
相同点 在一个 Vue3 单文件组件 (SFC)中,<script setup> 和 <script> 它们各自最多只能存在一个。 不同点 <script setup> 这个脚本块将被预处理为组件的 setup() 函数,这意味着它将为每一个(也可以说每一次)组件实例都执行。 <…...
Docker笔记-Docker搭建最新版zabbix服务端(2023-07-31)
前言 一开始问chartgpt上,搭建的思路是对的,但命令和细节有问题,最后还是依靠StackOverflow解决的。一开始在amd的linux上搭建好docker版的zabbix,但放到arm的机器上就报错了,原因是指令集不匹配,最后跑到…...
QT配合CSS隐藏按钮
第一种方法 在Qt的CSS样式表中,使用 visibility 属性来隐藏按钮。设置 visibility 为 hidden 不可见,而设置为 visible 则可见。 隐藏所有 QPushButton QPushButton {visibility: hidden; }隐藏特定的按钮,用按钮的名称或样式类进行定位就…...
2023亚太地区数学建模C题思路分析+模型+代码+论文
目录 1.2023亚太地区各题思路模型:比赛开始后,第一时间更新,获取见文末名片 3 常见数模问题常见模型分类 3.1 分类问题 3.2 优化问题 详细思路见此名片,开赛第一时间更新 1.亚太地区数学建模ABC题思路模型:9比赛开…...

Linguistic Steganalysis in Few-Shot Scenario论文阅读笔记
TIFS期刊 A类期刊 新知识点 Introduction Linguistic Steganalysis in Few-Shot Scenario模型是个预训练方法。 评估了四种文本加密分析方法,TS-CSW、TS-RNN、Zou、SeSy,用于分析和训练的样本都由VAE-Stego生产(编码方式使用AC编码)。 实验是对比在少样…...
详细学习Pyqt5的4种项目部件(Item Widget)
Pyqt5相关文章: 快速掌握Pyqt5的三种主窗口 快速掌握Pyqt5的2种弹簧 快速掌握Pyqt5的5种布局 快速弄懂Pyqt5的5种项目视图(Item View) 快速弄懂Pyqt5的4种项目部件(Item Widget) 快速掌握Pyqt5的6种按钮 快速掌握Pyqt5的10种容器&…...

notepad++ 插件JSONView安装
1,前提 开发过程中经常需要处理json格式语句,需要对json数据格式化处理,因为使用的是虚拟机内开发,所以没法连接外网,只能在本地电脑下载插件后,然后上传到虚拟机中,进行安装使用。 2…...

AKConv:具有任意采样形状和任意数目参数的卷积核
文章目录 摘要1、引言2、相关工作3、方法3.1、定义初始采样位置3.2、可变卷积操作3.3、扩展AKConv3.3、扩展AKConv 4、实验4.1、在COCO2017上的目标检测实验4.2、在VOC 712上的目标检测实验4.3、在VisDrone-DET2021上的目标检测实验4.4、比较实验4.5、探索初始采样形状 5、分析…...
如何使用C++开发集群服务
开发集群服务需要掌握以下技术: 分布式系统原理:了解集群的概念、工作原理、负载均衡、容错等相关概念。 网络编程:掌握Socket编程和HTTP协议等。 C编程:熟练掌握C语言的基础知识和STL等常用库。 多线程编程:了解线…...

docker安装以及idea访问docker
其他目录: docker 安装环境: https://blog.csdn.net/gd898989/article/details/134570167 docker 打包java包,并运行(有空更新) url “” docker 打包vue (有空更新) url “” docker 多服务 (…...

激光切割头组件中喷嘴的作用是什么
喷嘴是一个不可忽视的部件。尽管喷嘴并不起眼,却有着重要的作用;喷嘴一般是与激光切割头同轴的,且形状多样:圆柱形、锥形、缩放型等。 喷嘴的口径尺寸时不相同的,大口径的喷嘴对聚焦来的激光束没有很严苛的要求;而口径…...

腾讯云双11活动最后一天,错过再等一年!
腾讯云双11活动已经进入尾声,距离活动结束仅剩最后一天,记得抓住这次上云好时机,错过这次,就要等到下一年才能享受到这样的优惠力度了! 活动地址: 点此直达腾讯云双11活动主会场 活动详情: 1…...

Java实现飞翔的鸟小游戏
Java实现飞翔的鸟小游戏 1.准备工作 创建一个新的Java项目命名为“飞翔的鸟”,并在src中创建一个包命名为“com.qiku.bird",在这个包内分别创建4个类命名为**“Bird”、“BirdGame”、“Column”、“Ground”,并向需要的图片**素材导入…...

Python网络请求初级篇:使用Requests库抓取和解析数据
在网络编程中,请求和接收数据是最常见的任务之一。Python的Requests库提供了丰富的功能,使得HTTP请求变得非常简单。在本文中,我们将了解如何使用Requests库发起HTTP请求,并解析返回的数据。 一、安装Requests库 首先࿰…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...