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

news2024/11/26 5:22:09

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

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

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

相关文章

Apache Superset 身份认证绕过漏洞(CVE-2023-27524)

漏洞简介 Apache Superset是一个开源的数据可视化和数据探测平台&#xff0c;它基于Python构建&#xff0c;使用了一些类似于Django和Flask的Python web框架。提供了一个用户友好的界面&#xff0c;可以轻松地创建和共享仪表板、查询和可视化数据&#xff0c;也可以集成到其他…

二进制搭建 Kubernetes v1.20

k8s集群master01&#xff1a;192.168.179.25 kube-apiserver kube-controller-manager kube-scheduler etcd k8s集群master02&#xff1a;192.168.179.26 k8s集群node01&#xff1a;192.168.179.23 kubelet kube-proxy docker k8s集群node02&#xff1a;192.168.179.22 …

.env 环境变量使用,React项目中使用 .env.*等文件使用

一、公共.env环境变量 二、.env.*环境变量(例如&#xff1a;.env.test 环境变量) 公共 .env 环境变量 在项目开发中&#xff0c;我们不可避免的会需要使用 .env 环境变量&#xff0c;例如在定义接口 api 的 baseURL 时&#xff0c;会根据不同的环境&#xff0c;配置不同的根…

偶数分频器电路设计

目录 偶数分频器电路设计 1、偶数分频器电路简介 2、实验任务 3、程序设计 方法1&#xff1a; 3.1、8分频电路代码如下&#xff1a; 3.2、仿真验证 3.2.1、编写 TB 文件 3.2.2、仿真验证 方法2&#xff1a; 4、计数器进行分频 4.1、仿真测试 偶数分频器电路设计 分…

软件设计原则与设计模式

设计中各各原则同时兼有或冲突&#xff0c;不存在包含所有原则的设计 一&#xff1a;单一职责原则又称单一功能原则 核心&#xff1a;解耦和增强内聚性&#xff08;高内聚&#xff0c;低耦合&#xff09; 描述&#xff1a;类被修改的几率很大&#xff0c;因此应该专注于单一的…

YOLOv5 vs YOLOv8

1 概述 YOLOv8 是 ultralytics 公司在 2023 年 1月 10 号开源的 YOLOv5 的下一个重大更新版本。 https://github.com/ultralytics/yolov5 https://github.com/ultralytics/ultralytics 2 网络结构 YOLOv5 N/S/M/L/X 骨干网络的通道数设置使用同一套缩放系数&#xff1b; YOLO…

Axure教程——滑动解锁

本文将教大家如何用AXURE中的动态面板制作滑动解锁 一 、效果 预览地址&#xff1a;https://6dnu91.axshare.com 二、功能 滑动滑块从左到右&#xff0c;提示验证成功 三、制作 拖入一个动态面板组件&#xff0c;如图&#xff1a; 点击动态面板进入&#xff0c;拖入一个矩形…

【生态经济学】R语言机器学习方法在生态经济学领域中的实践技术

查看原文>>>基于R语言机器学习方法在生态经济学领域中的实践技术 近年来&#xff0c;人工智能领域已经取得突破性进展&#xff0c;对经济社会各个领域都产生了重大影响&#xff0c;结合了统计学、数据科学和计算机科学的机器学习是人工智能的主流方向之一&#xff0c…

RK3288 Android logo

一、Android 系统开机logo的修改 安卓系统的开机分为u-boot logo 和 kernel logo开机logo图片必须是 bmp 格式&#xff0c;并且分辨率必须为偶数将制作好的BMP格式logo图片放置Android源码kernel目录下&#xff0c;重新编译即可 二、Android logo常见问题分析 1、RK3288 Andr…

基于SSM+jsp的电子商城系统设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

IT云运维技术分享

1 运维体系 1.1 市场对运维的需求 时代发展到今天&#xff0c;社会的生活方式与生产方式的全面的数字化&#xff0c;无论是传统企业还是互联网企业&#xff0c;都在全面上云&#xff0c;这也意味着企业的关键业务乃至“身家性命”都已经全部放在 IT 系统之上&#xff0c;因此…

UWB自组网定位方案_基于UWB技术的消防应急救援定位解决方案

目前国内应急救援市场都是基于被动定位应用&#xff0c;在特殊情况下救援也大多处于单兵作战的情况&#xff0c;并不能及时知道自己和自己组员的位置信息和状态&#xff0c;且没有场景感知和室内外一体位置信息结合&#xff0c;使相关救援人员处于更加危险境地。本篇就带大家详…

【SWAT水文模型】Tips1:土地利用/土壤类型以全国数据分类

Tips1&#xff1a;土地利用/土壤类型以全国数据分类 1 土壤类型处理Step1 从全国土壤数据库中裁剪得到研究区域内土壤类型Step2 确定研究区域内重分类标准及类型 参考 1 土壤类型处理 直接对全国土壤类型数据进行分类&#xff0c;在SWAT模型中输入全国土壤类型&#xff0c;亦可…

【Linux】文件权限解析

一、Linux用户分类 Linux下有两种用户&#xff1a;超级用户&#xff08;root&#xff09;、普通用户 超级用户&#xff1a;可以再linux系统下做任何事情&#xff0c;不受限制 普通用户&#xff1a;在linux下做有限的事情。 超级用户的命令提示符是“#”&#xff0c;普通用户的…

近期煤矿事故及电力综合自动化系统的介绍

安科瑞虞佳豪 5月29日&#xff0c;山西灵石红杏鑫鼎泰煤业有限公司发生一起死亡1人的安全事故&#xff1b;5月24日&#xff0c;山西华阳集团新能股份有限公司二矿发生一起死亡1人的安全事故。 ​山西省应急管理厅、山西省地方煤矿安全监督管理局责令山西灵石红杏鑫鼎泰煤业有…

软考高级系统架构设计师(三) 基础知识之操作系统3文件管理

目录 文件管理 索引文件结构 位示图 ​树形目录结构 文件管理 文件管理&#xff0c;主要涉及文件的逻辑组织和物理组织&#xff0c;目录的结构和管理 索引文件结构 索引文件结构&#xff1a;通常是13个节点的结构&#xff0c;分为直接索引&#xff08;0-9&#xff09;&#…

星辰天合与中飞院合作 成立“民航高性能数据分析与存储联合实验室”

近日&#xff0c;星辰天合与中国民航飞行学院&#xff08;以下简称“中飞院”&#xff09;宣布合作成立“民航高性能数据分析与存储联合实验室”&#xff08;以下简称“存储实验室”&#xff09;&#xff0c;并由星辰天合 CTO 王豪迈与现任中飞院总飞行师的“中国民航英雄机长”…

Winfrom多语言切换

“ 实现多语言的切换原理和ResXResourceManager使用。” &#xff0c;时长00:08 实现多语言的切换原理就很简单了&#xff0c;例如默认是中文&#xff0c;from下就会有一个Form1.resx资源文件&#xff0c;所有的资源文件都是.resx。换个思路如果是WPF程序&#xff0c;那么资源文…

String类—javaSE

文章目录 1.常用方法1.1字符串构造1.2String对象的比较1.3字符串查找1.4转化1.5字符串替换1.6字符串拆分1.7字符串的截取1.8去掉字符串中的左右空格&#xff0c;保留中间空格 2.字符串常量池2.1 直接使用字符串常量进行赋值2.2通过new创建String类对象2.3 intern方法2.4String类…

韵达快递,你在玩我吗?请你不要挑战用户的底线!

这个周末真的是被韵达快递给气死了。 面对这样的服务&#xff0c;真的是不吐不快。 搞笑之处在于&#xff0c;表面功夫很到位&#xff0c;看似服务很全面&#xff0c;然后就是落实不到位。 为什么会被韵达快递气到呢&#xff1f;在网上买了 6 箱认养一头牛的儿童牛奶&#xff0…