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

这篇具有很好参考价值的文章主要介绍了驱动开发:基于事件同步的反向通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在之前的文章中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客户端,此时屏幕中即可看到滚动输出效果,如此一来就实现了循环传递参数的目的。

驱动开发:基于事件同步的反向通信文章来源地址https://www.toymoban.com/news/detail-491568.html

到了这里,关于驱动开发:基于事件同步的反向通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • DDD进阶_领域事件是什么?如何开展领域事件驱动开发工作?

    DDD从入门到精通,系列文章传送地址,请点击本链接。   目录 一、什么是领域事件 二、如何识别领域事件 三、领域事件的数据一致性 四、领域事件分类 1、微服务内的领域事件 2、微服务之间的领域事件 五、领域事件案例 六、领域事件总体架构图 1. 事件构建和发布 2、事

    2024年02月15日
    浏览(41)
  • 驱动开发常见的通信接口介绍

            本文将为您详细讲解驱动开发中常见的通信接口,以及它们的特点、区别和应用场景。在操作系统和硬件设备之间,通信接口扮演着至关重要的角色,它们定义了数据如何在软件和硬件之间传输和交互。          1. 串行通信接口(Serial Communication)       

    2024年03月14日
    浏览(48)
  • 如何用go写一个基于事件驱动的SSE的程序

    SSE(Serversentevents)是浏览器向服务器发送请求并保持长连接的技术,服务器通过长连接将数据推送到浏览器。SSE通常用于实时更新网页内容或获得服务器推送的通知。 下面是实现一个基于事件驱动的SSE程序的步骤: 创建一个HTTP服务器。 注册一个路由处理程序,用于处理SSE请求

    2024年02月08日
    浏览(41)
  • Github 用户查询案例【基于Vue2全局事件总线通信】

            本次案例是一个基于 Vue2 的全局事件总线通信的仿 Github 用户搜索模块,使用的接口是 Github 官方提供的搜索接口: https://api.github.com/search/users?q=xxx(发送请求时需要将输入的用户名称绑定替换掉xxx),如果对全局事件总线不太熟练的小伙伴可以看这篇文章: http:/

    2024年02月03日
    浏览(59)
  • 驱动开发:通过应用堆实现多次通信

    在前面的文章 《驱动开发:运用MDL映射实现多次通信》 LyShark教大家使用 MDL 的方式灵活的实现了内核态多次输出结构体的效果,但是此种方法并不推荐大家使用原因很简单首先内核空间比较宝贵,其次内核里面不能分配太大且每次传出的结构体最大不能超过 1024 个,而最终

    2024年02月05日
    浏览(44)
  • windows驱动开发7:应用程序和驱动程序的通信

    一、基础介绍 1.1 设备与驱动的关系 设备由驱动去创建,访问一个设备,是首先得访问驱动。如果驱动在卸载的时候没有删除符号,r3下也是不能去访问设备的。 驱动程序和系统其他组件之间的交互是通过给设备发送或者接受发给设备的请求来交互的。换句话说,一个没有任

    2023年04月08日
    浏览(51)
  • .NET6 项目使用RabbitMQ实现基于事件总线EventBus通信

    一、概念及介绍         通常通过使用事件总线实现来执行此发布/订阅系统。 事件总线可以设计为包含 API 的接口,该 API 是订阅和取消订阅事件和发布事件所需的。 它还可以包含一个或多个基于跨进程或消息通信的实现,例如支持异步通信和发布/订阅模型的消息队列或

    2024年04月28日
    浏览(53)
  • 驱动开发:通过MDL映射实现多次通信

    在前几篇文章中 LyShark 通过多种方式实现了驱动程序与应用层之间的通信,这其中就包括了通过运用 SystemBuf 缓冲区通信,运用 ReadFile 读写通信,运用 PIPE 管道通信,以及运用 ASYNC 反向通信,这些通信方式在应对 一收一发 模式的时候效率极高,但往往我们需要实现一次性吐

    2024年02月01日
    浏览(37)
  • STM32F103单片机通过SPI全双工通信协议与W25Q64(FLASH)进行通信【串行同步通信(数据线与时钟线配合),(一主多从模式)】附相关驱动代码详解

    1.W25Qxx系列是一种低成本、小型化、使用简单的 非易失性存储器 ,常应用于数据存储、字库存储、固件程序存储等场景 2.存储介质: Nor Flash(闪存) 3.时钟频率:80MHz / 160MHz (Dual SPI) / 320MHz (Quad SPI) 4.存储容量(24位地址): W25Q40: 4Mbit / 512KByte W25Q80: 8Mbit / 1MByte W25Q16: 16

    2024年04月13日
    浏览(61)
  • 驱动开发:通过PIPE管道与内核层通信

    在本人前一篇博文 《驱动开发:通过ReadFile与内核层通信》 详细介绍了如何使用应用层 ReadFile 系列函数实现内核通信,本篇将继续延申这个知识点,介绍利用 PIPE 命名管道实现应用层与内核层之间的多次通信方法。 什么是PIPE管道? 在Windows编程中,数据重定向需要用到管道

    2024年02月20日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包