驱动开发:基于事件同步的反向通信

在之前的文章中LyShark一直都在教大家如何让驱动程序与应用层进行正向通信,而在某些时候我们不仅仅只需要正向通信,也需要反向通信,例如杀毒软件如果驱动程序拦截到恶意操作则必须将这个请求动态的转发到应用层以此来通知用户,而这种通信方式的实现有多种,通常可以使用创建Socket套接字的方式实现,亦或者使用本章所介绍的通过事件同步的方法实现反向通信。

基于事件同步方式实现的通信需要用的最重要函数IoCreateNotificationEvent()这是微软定为开发者提供的。

IoCreateNotificationEvent 例程创建或打开一个命名通知事件,用于通知一个或多个执行线程已发生事件。

PKEVENT IoCreateNotificationEvent(
  [in]  PUNICODE_STRING EventName,
  [out] PHANDLE         EventHandle
);

其中的第二个参数EventHandle指向返回事件对象的内核句柄的位置的指针。此处为了能更好的接收和管理指针与进程之间的关系我们最好定义一个DEVICE_EXTEN结构体。

// 自定义设备扩展
typedef struct
{
	HANDLE  hProcess;         // HANDLE
	PKEVENT pkProcessEvent;   // 事件对象
	HANDLE  hProcessId;       // PID
	HANDLE  hpParProcessId;   // PPID
	BOOLEAN bIsCreateMark;    // Flag
}DEVICE_EXTEN, *PDEVICE_EXTEN;

驱动入口处PsSetCreateProcessNotifyRoutine则用于创建一个进程回调,该回调函数被指定为pMyCreateProcessThreadRoutine当回调函数被创建后,一旦有新进程创建则会执行函数内部的具体流程。

如代码所示,在pMyCreateProcessThreadRoutine函数内首先通过(PDEVICE_EXTEN)GlobalDevObj->DeviceExtension得到了自定义设备扩展指针,接着将当前进程的PID,PPID,isCreate等属性赋予到扩展指针中,当一切准备就绪后,通过调用KeSetEvent将当前进程事件设置为有信号状态,设置后重置为默认值。

// 自定义回调函数
VOID pMyCreateProcessThreadRoutine(IN HANDLE pParentId, HANDLE hProcessId, BOOLEAN bisCreate)
{
	PDEVICE_EXTEN pDeviceExten = (PDEVICE_EXTEN)GlobalDevObj->DeviceExtension;

	// 将进行信息依次复制到结构体中
	pDeviceExten->hProcessId = hProcessId;
	pDeviceExten->hpParProcessId = pParentId;
	pDeviceExten->bIsCreateMark = bisCreate;

	// 设置为有信号
	KeSetEvent(pDeviceExten->pkProcessEvent, 0, FALSE);

	// 重置状态信号
	KeResetEvent(pDeviceExten->pkProcessEvent);
}

此时由于客户端中通过OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME)打开了内核对象,并通过WaitForSingleObject(hProcessEvent, INFINITE)一直在等待事件,一旦内核驱动KeSetEvent(pDeviceExten->pkProcessEvent, 0, FALSE)设置为有信号状态,则应用层会通过DeviceIoControl向内核层发送IOCTL控制信号并等待接收数据。

此时主派遣函数DisPatchIoControl被触发执行,通过(PPROCESS_PTR)pUserOutPutBuffer获取到应用层缓冲区设备指针,并依次通过pBuffer->的方式设置参数,最后返回状态码,此时应用层PROCESS_PTR中也就得到了进程创建的相关信息。

pBuffer = (PPROCESS_PTR)pUserOutPutBuffer;
uIoControl = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
uReadLen = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
uWriteLen = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;

switch (uIoControl)
{
case IOCTL:
	pDeviceExten = (PDEVICE_EXTEN)GlobalDevObj->DeviceExtension;
	pBuffer->hProcessId = pDeviceExten->hProcessId;
	pBuffer->hpParProcessId = pDeviceExten->hpParProcessId;
	pBuffer->bIsCreateMark = pDeviceExten->bIsCreateMark;
	break;
default:
	ntStatus = STATUS_INVALID_PARAMETER;
	uWriteLen = 0;
	break;
}

如上就是内核层与应用层的部分代码功能分析,接下来我将完整代码分享出来,大家可以自行测试效果。

驱动程序WinDDK.sys完整代码;

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#include <ntifs.h>
#include <ntstrsafe.h>

#define IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)

UNICODE_STRING GlobalSym = { 0 };
PDEVICE_OBJECT GlobalDevObj;

// 自定义设备扩展
typedef struct
{
	HANDLE  hProcess;         // HANDLE
	PKEVENT pkProcessEvent;   // 事件对象
	HANDLE  hProcessId;       // PID
	HANDLE  hpParProcessId;   // PPID
	BOOLEAN bIsCreateMark;    // Flag
}DEVICE_EXTEN, *PDEVICE_EXTEN;

// 自定义结构体(临时)
typedef struct
{
	HANDLE hProcessId;
	HANDLE hpParProcessId;
	BOOLEAN bIsCreateMark;
}PROCESS_PTR, *PPROCESS_PTR;

// 自定义回调函数
VOID pMyCreateProcessThreadRoutine(IN HANDLE pParentId, HANDLE hProcessId, BOOLEAN bisCreate)
{
	PDEVICE_EXTEN pDeviceExten = (PDEVICE_EXTEN)GlobalDevObj->DeviceExtension;

	// 将进行信息依次复制到结构体中
	pDeviceExten->hProcessId = hProcessId;
	pDeviceExten->hpParProcessId = pParentId;
	pDeviceExten->bIsCreateMark = bisCreate;

	// 设置为有信号
	KeSetEvent(pDeviceExten->pkProcessEvent, 0, FALSE);

	// 重置状态信号
	KeResetEvent(pDeviceExten->pkProcessEvent);
}

// 默认派遣函数
NTSTATUS DisPatchComd(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
	pIrp->IoStatus.Information = 0;
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);

	return pIrp->IoStatus.Status;
}

// 主派遣函数
NTSTATUS DisPatchIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
	NTSTATUS ntStatus;
	PIO_STACK_LOCATION pIrpStack;
	PVOID pUserOutPutBuffer;
	PPROCESS_PTR pBuffer;
	ULONG uIoControl = 0;
	ULONG uReadLen;
	ULONG uWriteLen;
	PDEVICE_EXTEN pDeviceExten;

	pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
	pUserOutPutBuffer = pIrp->AssociatedIrp.SystemBuffer;

	pBuffer = (PPROCESS_PTR)pUserOutPutBuffer;
	uIoControl = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
	uReadLen = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
	uWriteLen = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;

	switch (uIoControl)
	{
	case IOCTL:
		pDeviceExten = (PDEVICE_EXTEN)GlobalDevObj->DeviceExtension;
		pBuffer->hProcessId = pDeviceExten->hProcessId;
		pBuffer->hpParProcessId = pDeviceExten->hpParProcessId;
		pBuffer->bIsCreateMark = pDeviceExten->bIsCreateMark;
		break;
	default:
		ntStatus = STATUS_INVALID_PARAMETER;
		uWriteLen = 0;
		break;
	}

	pIrp->IoStatus.Information = uWriteLen;
	pIrp->IoStatus.Status = ntStatus;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return ntStatus;
}

// 卸载驱动
VOID DriverUnLoad(PDRIVER_OBJECT pDriverObject)
{
	NTSTATUS ntStatus;
	UNICODE_STRING SymboLicLinkStr = { 0 };

	// 删除符号链接
	ntStatus = RtlUnicodeStringInit(&SymboLicLinkStr, L"\\DosDevices\\Symboliclnk");
	ntStatus = IoDeleteSymbolicLink(&SymboLicLinkStr);

	// 注销进程消息回调
	PsSetCreateProcessNotifyRoutine(pMyCreateProcessThreadRoutine, TRUE);
	IoDeleteDevice(pDriverObject->DeviceObject);
}

// 入口函数
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath)
{
	NTSTATUS ntStatus = NULL;
	PDEVICE_OBJECT pDeviceObject = NULL;
	UNICODE_STRING uDeviceName = { 0 };
	UNICODE_STRING uEventName = { 0 };

	// 初始化字符串
	ntStatus = RtlUnicodeStringInit(&uDeviceName, L"\\Device\\ProcLook");
	ntStatus = RtlUnicodeStringInit(&GlobalSym, L"\\DosDevices\\Symboliclnk");
	ntStatus = RtlUnicodeStringInit(&uEventName, L"\\BaseNamedObjects\\ProcLook");
	DbgPrint("hello lyshark.com");
	if (!NT_SUCCESS(ntStatus))
	{
		return ntStatus;
	}

	// 创建设备
	ntStatus = IoCreateDevice(pDriver,sizeof(DEVICE_EXTEN),&uDeviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&pDeviceObject);
	DbgPrint("[LyShark] 创建设备对象");

	if (!NT_SUCCESS(ntStatus))
	{
		IoDeleteDevice(pDeviceObject);
		return ntStatus;
	}
	pDriver->Flags |= DO_BUFFERED_IO;
	GlobalDevObj = pDeviceObject;

	// 获取设备扩展指针,并IoCreateNotificationEvent创建一个R3到R0的事件
	PDEVICE_EXTEN pDeviceExten = (PDEVICE_EXTEN)pDeviceObject->DeviceExtension;
	pDeviceExten->pkProcessEvent = IoCreateNotificationEvent(&uEventName, &pDeviceExten->hProcess);
	KeClearEvent(pDeviceExten->pkProcessEvent);
	DbgPrint("[LyShark] 创建事件回调");

	// 创建符号链接
	ntStatus = IoCreateSymbolicLink(&GlobalSym, &uDeviceName);
	if (!NT_SUCCESS(ntStatus))
	{
		IoDeleteDevice(pDeviceObject);
		return ntStatus;
	}

	// 注册进程创建回调
	ntStatus = PsSetCreateProcessNotifyRoutine(pMyCreateProcessThreadRoutine, FALSE);
	DbgPrint("[LyShark] 创建进程回调");
	if (!NT_SUCCESS(ntStatus))
	{
		IoDeleteDevice(pDeviceObject);
		return ntStatus;
	}

	// 初始化派遣函数
	for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
	{
		pDriver->MajorFunction[i] = DisPatchComd;
	}
	pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DisPatchIoControl;

	// 关闭驱动
	pDriver->DriverUnload = DriverUnLoad;
	return ntStatus;
}

应用层客户端程序lyshark.exe完整代码;

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#include <iostream>
#include <Windows.h>

#define EVENT_NAME L"Global\\ProcLook"
#define IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)

typedef struct
{
	HANDLE hProcessId;
	HANDLE hpParProcessId;
	BOOLEAN bIsCreateMark;
}PROCESS_PTR, *PPROCESS_PTR;

int main(int argc, char* argv[])
{
	PROCESS_PTR Master = { 0 };
	PROCESS_PTR Slave = { 0 };
	DWORD dwRet = 0;
	BOOL bRet = FALSE;

	// 打开驱动设备对象
	HANDLE hDriver = CreateFile(L"\\\\.\\Symboliclnk",GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if (hDriver == INVALID_HANDLE_VALUE)
	{
		return 0;
	}

	// 打开内核事件对象
	HANDLE hProcessEvent = OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);

	if (NULL == hProcessEvent)
	{
		return 0;
	}

	while (TRUE)
	{
		// 等待事件
		WaitForSingleObject(hProcessEvent, INFINITE);

		// 发送控制信号
		bRet = DeviceIoControl(hDriver,IOCTL,NULL,0,&Master,sizeof(Master),&dwRet,NULL);
		if (!bRet)
		{
			return 0;
		}

		if (bRet)
		{
			if (Master.hpParProcessId != Slave.hpParProcessId || Master.hProcessId != Slave.hProcessId || Master.bIsCreateMark != Slave.bIsCreateMark)
			{
				if (Master.bIsCreateMark)
				{
					printf("[LyShark] 父进程: %d | 进程PID: %d | 状态: 创建进程 \n", Master.hpParProcessId, Master.hProcessId);
				}
				else
				{
					printf("[LyShark] 父进程: %d | 进程PID: %d | 状态: 退出进程 \n", Master.hpParProcessId, Master.hProcessId);
				}
				Slave = Master;
			}
		}
		else
		{
			break;
		}
	}

	CloseHandle(hDriver);
	return 0;
}

手动编译这两个程序,将驱动签名后以管理员身份运行lyshark.exe客户端,此时屏幕中即可看到滚动输出效果,如此一来就实现了循环传递参数的目的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

多模态学习

什么是多模态学习&#xff1f; 模态 模态是指一些表达或感知事物的方式&#xff0c;每一种信息的来源或者形式&#xff0c;都可以称为一种模态 视频图像文本音频 多模态 多模态即是从多个模态表达或感知事物 多模态学习 从多种模态的数据中学习并且提升自身的算法 多…

Nacos架构与原理 - 寻址机制

文章目录 前提设计MemberLookup内部实现单机寻址 StandaloneMemberLookup文件寻址 FileConfigMemberLookup地址服务器寻址 AddressServerMemberLookup 未来可扩展点 前提 Nacos 支持单机部署以及集群部署 针对单机模式&#xff0c;Nacos 只是自己和自己通信&#xff1b;对于集…

关系数据库SQL数据查询

关系数据库SQL数据查询 数据查询 一、单表查询 1.查询仅涉及一个表&#xff0c;选择表中的若干列 [例1] 查询全体学生的学号与姓名。SELECT Sno,SnameFROM Student; [例2] 查询全体学生的姓名、学号、所在系。SELECT Sname,Sno,SdeptFROM Student;查询全部列 选出所有属…

文件系统考古 3:1994 - The SGI XFS Filesystem

在 1994 年&#xff0c;论文《XFS 文件系统的可扩展性》发表了。自 1984 年以来&#xff0c;计算机的发展速度变得更快&#xff0c;存储容量也增加了。值得注意的是&#xff0c;在这个时期出现了更多配备多个 CPU 的计算机&#xff0c;并且存储容量已经达到了 TB 级别。对于这些…

机器学习实践(1.2)XGBoost回归任务

前言 XGBoost属于Boosting集成学习模型&#xff0c;由华盛顿大学陈天齐博士提出&#xff0c;因在机器学习挑战赛中大放异彩而被业界所熟知。相比越来越流行的深度神经网络&#xff0c;XGBoost能更好的处理表格数据&#xff0c;并具有更强的可解释性&#xff0c;还具有易于调参…

SpringCloud微服务(二)网关GateWay、Docker、Dockerfile、Linux操作超详细

目录 统一网关GateWay 搭建网关服务的步骤 1、引入依赖 2、编写路由配置及nacos地址 路由断言工厂Route Oredicate Factory 路由过滤器配置 全局过滤器GlobalFilter 过滤器执行顺序 跨域问题处理 Docker ​编辑 Docker与虚拟机 镜像和容器 Docker的安装 启动docke…

MSP432学习笔记11:定时器A的结构\基地址\函数汇总理解

今日得以继续我的电赛MSP432学习之路&#xff1a;所用开发板MSP432P401R 定时器是任何单片机开发板十分重要的模块&#xff0c;在几日的学习使用过程中&#xff0c;本人也对其使用原理等产生过许多疑问&#xff0c;他究竟是怎么存储计数值、捕获值的&#xff1f;一个定时器四个…

8.2 电压比较器(1)

电压比较器是对输入信号进行鉴幅与比较的电路&#xff0c;是组成非正弦波发生电路的基本单元电路&#xff0c;在测量和控制中有着相当广泛的应用。 一、概述 1、电压比较器的电压传输特性 电压比较器的输出电压 u O u_{\scriptscriptstyle O} uO​ 与输入电压 u I u_{\scr…

网络层:虚拟专用网VPN和网络地址转换NAT

1.网络层&#xff1a;虚拟专用网VPN和网络地址转换NAT 笔记来源&#xff1a; 湖科大教书匠&#xff1a;虚拟专用网VPN和网络地址转换NAT 声明&#xff1a;该学习笔记来自湖科大教书匠&#xff0c;笔记仅做学习参考 1.1 虚拟专用网VPN 专用网和公用网的特点 专用网络&#xff…

Springboot集成magic-api

目录 1、前言 2、springboot集成magic-api 2.1、添加maven依赖 2.2、application.yml配置 2.3、编写测试接口 2.4、启动程序&#xff0c;访问接口 2.5、magic-api脚本 3、magic-api其他语法 4、注意事项 1、前言 今天项目中遇到一个问题&#xff0c;springboot后端项目…

探索ChatGPT:了解语言模型在对话系统中的应用

第一章&#xff1a;引言 在当今数字化时代&#xff0c;人工智能技术的迅猛发展使得对话系统成为一个备受关注的领域。随着语言模型的进步&#xff0c;像ChatGPT这样的模型正在改变我们与计算机进行交流的方式。本文将探索ChatGPT作为一种语言模型在对话系统中的应用&#xff0…

简化 Hello World:Java 新写法要来了

OpenJDK 的 JEP 445 提案正在努力简化 Java 的入门难度。 这个提案主要是引入 “灵活的 Main 方法和匿名 Main 类” &#xff0c;希望 Java 的学习过程能更平滑&#xff0c;让学生和初学者能更好地接受 Java 。 提案的作者 Ron Pressler 解释&#xff1a;现在的 Java 语言非常…

Flutter 笔记 | Flutter 核心原理(三)布局(Layout )过程

布局过程 Layout&#xff08;布局&#xff09;过程主要是确定每一个组件的布局信息&#xff08;大小和位置&#xff09;&#xff0c;Flutter 的布局过程如下&#xff1a; 父节点向子节点传递约束&#xff08;constraints&#xff09;信息&#xff0c;限制子节点的最大和最小宽…

【实战与杂谈】本地搭建自己的游戏王卡片生成器

声明&#xff1a; 1.游戏王卡片制作器本身就是由【kooriookami】开发的&#xff0c;用于DIY卡片因此我只是原有功能再现并不会追加新功能 2.其次数据和卡图均来源于网络&#xff0c;因此我也只提供网络能获取该内容的途径&#xff0c;并不会预先准备好 最近一直没有时间看回复…

SpringBoot的配置环境属性

SpringBoot的配置环境属性 在本文中&#xff0c;我们将讨论SpringBoot的配置环境属性。我们将了解如何使用这些属性来配置我们的应用程序&#xff0c;以便在不同的环境中运行。我们还将了解如何使用SpringBoot的配置文件来管理这些属性。最后&#xff0c;我们将介绍一些最佳实…

激活函数ReLU和SiLU的区别

文章目录 前言ReLU&#xff08;Rectified Linear Unit&#xff09;Leaky ReLUFReLU&#xff08;Flatten ReLU&#xff09;SiLU&#xff08;Sigmoid Linear Unit&#xff09;总结 前言 在这里&#xff0c;我就简单写一下两个激活函数的概念以及区别&#xff0c;详细的过程可以看…

【C++详解】——红黑树

目录 红黑树的概念 红黑树的性质 红黑树节点的定义 红黑树的结构 红黑树的插入操作 情况一 情况二 情况三 红黑树的验证 红黑树的查找 红黑树与AVL树的比较 红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示…

校园网WiFi IPv6免流上网

ipv6的介绍 IPv6是国际协议的最新版本&#xff0c;用它来取代IPv4主要是为了解决IPv4网络地址枯竭的问题&#xff0c;也在其他很多方面对IPv4有所改进&#xff0c;比如网络的速度和安全性。 IPv4是一个32位的地址&#xff0c;随着用户的增加在2011年国家报道说IPv4的网络地址即…

SpringBoot整合模板引擎Thymeleaf(2)

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 概述 Thymeleaf十分类似于JSP中使用的EL表达式。整体而言&#xff0c;Thymeleaf简洁、优雅、高效&#xff1b;非常适合小型项目的快速开发。 Thymeleaf常用标签简述 在此…

Socket安全(一)

文章目录 1. 安全Socket2. 保护通信3. 创建安全客户端Socket4. 选择密码组5. 事件处理器6. 会话管理 1. 安全Socket 前面介绍了Socket的基本使用&#xff0c;这里开始介绍Socket的安全问题&#xff0c;作为一个Internet用户&#xff0c;你确实有一些保护手段可以保护自己的隐私…