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, &ethread);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;
}

运行后则可监控到系统总所有线程的创建与退出,效果如下所示:

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

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

相关文章

H3C路由器基本配置命令

1、system-view 进入系统视图 2、sysname R1 配置路由器名字为R1 3、display clock 查看当前系统时间 4、clock datetime 00:00:00 2/26/2023 用户模式下修改系统时间 配置控制台密码 Console&#xff1a; 1、user-interface aux0 在系统模式下进入图接口 2、authentication-mo…

2023亚太赛c题完整思路数据 数学建模亚太

Question 1: Analyze the main factors that affect the development of new energy electric vehicles in China, establish a mathematical model, and describe the impact of these factors on the development of new energy electric vehicles in China. 问题1:分析影响…

office 365企业版安装教程

1.下载所需工具&#xff08;防火墙和防毒软件记得关闭&#xff09; 下载链接&#xff1a;所需文件 2.安装激活office 1.安装 office tool plus 2.已安装过office 先进行office的移除&#xff0c;再进行未安装office的步骤进行 3.未安装过office 1.设置部署 按照以下来进行安…

Linux命令(130)之hwclock

linux命令之hwclock 1.hwclock介绍 linux命令hwclock是用来显示硬件时钟 2.hwclock用法 hwclock [参数] hwclock参数 参数说明-s让系统时间同步硬件时间-w让硬件时间同步系统时间 3.实例 3.1.同步服务器时钟时间 命令&#xff1a; ntpdate pool.ntp.org [rootrhel77 ~…

【vin 国标正则校验】

规则一 var checkVINfunction(VIN){if(typeof(VIN)!string) return false;if(VIN.length!17) return false;VINVIN.toUpperCase();RE/^[A-HJ-NPR-Z\d]{8}[X\d][A-HJ-NPR-Z\d]{3}\d{5}$/if(!RE.test(VIN)) return false;let cOT{0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:1,B…

360:流氓or保家卫国的勇士?

你曾用过360吗&#xff0c;这个在国内名声不好的杀毒软件&#xff0c;却是令国外黑客闻风丧胆的存在。 首先&#xff0c;在电脑病毒刚兴起的年代&#xff0c;杀毒软件是要收费的&#xff0c;当时盛行的瑞星和金山就是采用的付费模式&#xff0c;而就在2006年&#xff0c;奇虎…

C/C++通过位操作实现2个uint32_t合并为uint64_t

#include <iostream> using namespace std;int main() {uint32_t a 10;uint32_t b 600;//先将uint32_t的a转为uint64_t&#xff0c;此时a前面32位都是0&#xff0c;然后左移32位&#xff0c;此时右32位为0&#xff0c;最后加上uint32_t类型的b&#xff0c;填充右32位的…

解决Activiti5.22流程图部署在Windows上正常,但在linux上部署后出现中文变方块的问题

总结/朱季谦 楼主最近在做公司的工作流平台&#xff0c;发现一个很无语的事情&#xff0c;Activiti5.22的流程图在Windows环境上部署&#xff0c;是可以正常查看的&#xff0c;但发布到公司的Linux服务器上后&#xff0c;在上面进行流程图在线部署时&#xff0c;发现中文都变成…

2023亚太杯数学建模C题思路代码 - 我国新能源电动汽车的发展趋势

1 赛题 问题C 我国新能源电动汽车的发展趋势 新能源汽车是指以先进技术原理、新技术、新结构的非常规汽车燃料为动力来源( 非常规汽车燃料指汽油、柴油以外的燃料&#xff09;&#xff0c;将先进技术进行汽车动力控制和驱动相结 合的汽车。新能源汽车主要包括四种类型&#x…

一套开源、强大且美观的WPF UI控件库 - HandyControl

前言 今天给大家推荐一套开源、强大且美观的WPF UI控件库&#xff1a;HandyControl。 WPF介绍 WPF 是一个强大的桌面应用程序框架&#xff0c;用于构建具有丰富用户界面的 Windows 应用。它提供了灵活的布局、数据绑定、样式和模板、动画效果等功能&#xff0c;让开发者可以创…

关于Redis底层的两个问题

1. 为什么Redis不共享包含字符串的对象&#xff1f; 当服务器考虑将一个共享对象设置为键的值对象时&#xff0c;程序首先需要检查给定的共享对象和键想要创建的目标对象是否完全相同&#xff0c;只有在共享对象和目标对象完全相同的情况下&#xff0c;程序才会将共享对象用作…

SOEM主站开发篇(3):为APP程序添加命令

0 工具准备 1.SOEM-1.4.0源码(官网:http://openethercatsociety.github.io/) 2.Linux开发板(本文为正点原子I.MX6U ALPHA开发板) 3.交叉编译工具(arm-linux-gnueabihf-gcc) 4.cmake(版本不得低于3.9,本文为3.9.2) 5.Ubuntu 16.04(用于编译生成Linux开发板的可执行文…

【追求卓越06】算法--递归

引导 递归算法算是我们比较常用的一种算法。但是想用好并不简单。本章我不再介绍简单的概念&#xff0c;主要讲解递归算法的优缺点和如何用递归写代码。 个人爱好 其实相对于使用while循环&#xff0c;我更喜欢使用递归算法。为什么呢&#xff1f; 使用递归算法代码往往会变…

Java语言中的控制流程

控制流程是编程中的重要概念之一&#xff0c;它允许程序根据条件执行不同的代码块或重复执行特定的代码块。在Java中&#xff0c;控制流程由条件语句和循环语句组成。本文将详细介绍Java中的条件语句&#xff08;if语句和switch语句&#xff09;和循环语句&#xff08;for循环、…

MySQL用户与权限管理

快捷查看指令 ctrlf 进行搜索会直接定位到需要的知识点和命令讲解&#xff08;如有不正确的地方欢迎各位小伙伴在评论区提意见&#xff0c;博主会及时修改&#xff09; MySQL用户与权限管理 登录 #本地登录 mysql -uroot -p123456#远程登录 #客户端语法&#xff1a;mysql -…

聚观早报 |快手Q3营收;拼多多杀入大模型;Redmi K70E开启预约

【聚观365】11月23日消息 快手Q3营收 拼多多杀入大模型 Redmi K70E开启预约 华为nova 12系列或下周发布 亚马逊启动“AI就绪”新计划 快手Q3营收 财报显示&#xff0c;快手第三季度营收279亿元&#xff0c;同比增长20.8%&#xff1b;期内盈利21.8亿元&#xff0c;去年同期…

猫罐头多久喂一次?好用的猫罐头牌子推荐

猫爱吃猫罐头&#xff0c;包含各种美味&#xff0c;提供营养和口感。但喂猫吃罐头需技巧和耐心&#xff0c;以确保猫健康快乐成长。 作为一个从业宠物营养师7年的人&#xff0c;可以说对于猫咪的食物很有研究和猫罐头品牌选购上&#xff0c;我有自己的见解。 一、猫罐头多久喂…

shell之wc命令

shell之wc命令 Linux中的wc命令是一个用于统计给定文件中的字节数、字数和行数的工具。它也可以从标准输入读取数据并统计。 wc命令的语法为&#xff1a; wc [选项] 文件... 如果没有给出文件名&#xff0c;则从标准输入读取。wc同时也给出所有指定文件的总统计数。wc命令的选…

40、Flink 的Apache Kafka connector(kafka source 和sink 说明及使用示例) 完整版

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

循环神经网络(RNN)实现股票预测

文章目录 一、前言二、前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;2. 导入数据 四、数据预处理1.归一化2.设置测试集训练集 五、构建模型六、激活模型七、训练模型八、结果可视化1.绘制loss图2.预测3.评估 一、前言 我的环境&#xff1a; 语言环…