例子驱动通信基础架构

1.Ring0编写驱动层代码:

//codemsg.h 定义通信控制代码
#ifndef _DEFINE_H_
#define _DEFINE_H_

// _number:    0 -> 2047 : reserved for Microsoft 微软保留
//             2047 -> 4095 : reserved for OEMs 用户自己定义
#define CODEMSG(_number) CTL_CODE(FILE_DEVICE_UNKNOWN, _number , METHOD_BUFFERED,                                FILE_READ_DATA | FILE_WRITE_DATA)
//定义控制码
#define INIT_FILE_NAME 2047

#endif

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Ring0.h
#ifndef _KERNEL_MODULE_H_
#define _KERNEL_MODULE_H_

#include <ntifs.h>
#include "codemsg.h"

//设备对象的名称
#define DEVICE L"\\Device\\www.AntiGameProtect.com"

//链接符号的名称
#define DOSDEVICE L"\\DosDevices\\www.AntiGameProtect.com"

PDEVICE_OBJECT DriverDeviceObject;

#endif

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Ring0.c
#include "Ring0.h"

//驱动卸载例程函数,在这里释放一些资源。
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
	UNICODE_STRING DeviceName;
	UNICODE_STRING DosDeviceName; 

	//删除符号链接
	RtlInitUnicodeString(&DosDeviceName, DOSDEVICE);
	IoDeleteSymbolicLink(&DosDeviceName );

	//删除驱动对象
	if(DriverDeviceObject != NULL)
		IoDeleteDevice(DriverDeviceObject);

	DbgPrint("驱动卸载成功!\r\n");
}

//默认的例程处理函数
NTSTATUS IODispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	return STATUS_SUCCESS;
}

//验证一个WCHAR内容的指针能否够訪问
BOOLEAN ValidateWCHARString(WCHAR *pwzStr, ULONG_PTR Length)
{
	ULONG i;

	__try
	{
		//第一步推断指针和大小是否为NULL,是的话就不是必需验证了
		if (*pwzStr == NULL || Length == 0)
		{
			return FALSE;
		}

		//以length长度循环检查指针pwzStr里面的值
		for (i = 0; i < Length; i++)
		{
			//检查内存能否够訪问。
			if (!MmIsAddressValid((PUCHAR)pwzStr + i))
			{
				//仅仅要有一个字节是不可读取,就失败
				return FALSE;
			}
		}

	}__except(EXCEPTION_EXECUTE_HANDLER)
	{
		//触发了异常
		return FALSE;
	}

	return TRUE;
}

//IRP通信例程处理函数
NTSTATUS IOManager(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	//获取当前IrpStack,通过读取其结构成员,取出我们须要的控制码IRPcode
	PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(Irp);

	//获取控制码IRPcode
	ULONG IRPcode = StackLocation->Parameters.DeviceIoControl.IoControlCode;  

	WCHAR *buf;
	SIZE_T size;
	WCHAR *pwzCopyBuf = NULL;

	//获取应用层传进来的内存缓冲区
	buf = (WCHAR*)Irp->AssociatedIrp.SystemBuffer;

	//内存缓冲区的字节长度
	size  = (SIZE_T)Irp->Size;

	//设置Irp的状态
	Irp->IoStatus.Status = STATUS_SUCCESS; 

	switch(IRPcode)
	{
		case CODEMSG(INIT_FILE_NAME):

		//从应用层传进来的buf,你无法预知这个值能否够訪问,所以,这里要验证我们传递进来的buf的有效性,才干够在驱动层訪问buf
		//所以,这里我写了一个ValidateWCHARString来验证这个变量
		__try{
			//推断Buffer的有效性
			if (ValidateWCHARString(buf, size))
			{

				//提示-应用层数据传到了驱动层
				DbgPrint("Buf ==> %ws:%d\r\n", buf, size);

				//申请内存。相似应用层的new,并给于标识'fp'
				pwzCopyBuf = (WCHAR*)ExAllocatePoolWithTag(NonPagedPool, size, 'fp');

				//假设申请内存成功
				if (pwzCopyBuf)
				{
					//内存初始化
					memset(pwzCopyBuf, 0, size);

					//copy到我们新申请的内存
					memcpy(pwzCopyBuf,buf,size);

					//显示从应用层获取到的字符串信息
					DbgPrint("CopyBuf ==> %ws\r\n", pwzCopyBuf);

					//在驱动以下用C语言来写,就要遵守windows的规则。申请的内存,必须要释放。
					//要记得释放内存
					ExFreePool(pwzCopyBuf);
				}
			}
		}
		__except (EXCEPTION_EXECUTE_HANDLER)
		{
			//获取异常的状态码
			Irp->IoStatus.Status = GetExceptionCode();
		}
		break;

	default:
		Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;                       

	}

	//设置Irp的返回码
	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	return Irp->IoStatus.Status;
}

//驱动的入口函数DriverEntry
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING theRegistryPath)
{
	UNICODE_STRING DeviceName;
	UNICODE_STRING DosDeviceName;
	NTSTATUS status;

	//初始化驱动符号名
	//UNICODE_STRING是一个结构体,相似win32里面的结构体。比方SYSTEMTIME
	//在Win系统下,内核的结构体都是能够通过windbg或者wrk获得
	/*
	lkd> dt_unicode_string
	nt!_UNICODE_STRING
	+0x000 Length           : Uint2B //文本长度
	+0x002 MaximumLength    : Uint2B //最大长度
	+0x004 Buffer           : Ptr32 Uint2B //文本内容。是unicode类型,即WCHAR
	*/

	//设备名称字符串
	RtlInitUnicodeString(&DeviceName, DEVICE);
	//符号链接字符串
	RtlInitUnicodeString(&DosDeviceName, DOSDEVICE);

	//创建设备对象
	status = IoCreateDevice(
		DriverObject,        // ptr to caller object
		0,                   // extension device allocated byte number
		&DeviceName,         // device name
		FILE_DEVICE_UNKNOWN,
		0,                   // no special caracteristics
		FALSE,               // we can open many handles in same time
		&DeviceObject);		 // [OUT] ptr to the created object

	if (!NT_SUCCESS(status))
	{
		return STATUS_NO_SUCH_DEVICE;
	}
	//相同也须要一个符号链接。不然会影响到驱动和应用层的通信
	status = IoCreateSymbolicLink(&DosDeviceName,&DeviceName);
	if(!NT_SUCCESS(status))
	{
		IoDeleteDevice(DriverDeviceObject);
		return STATUS_NO_SUCH_DEVICE;
	}   

	//设置驱动卸载例程函数
	DriverObject->DriverUnload = DriverUnload;

	//IRP_MJ_CREATE。响应的是应用层函数CreateFile,应用层调用这个函数就会进入这个例程
	DriverObject->MajorFunction[IRP_MJ_CREATE] = IODispatch;

	//以下的分别相应应用层CloseHandle、ReadFile、WriteFile函数
	DriverObject->MajorFunction[IRP_MJ_CLOSE]  = IODispatch;
	DriverObject->MajorFunction[IRP_MJ_READ]   = IODispatch;
	DriverObject->MajorFunction[IRP_MJ_WRITE]  = IODispatch;

	//一般我们跟应用层通信,都是通过IRP_MJ_DEVICE_CONTROL例程,这个例程相应的是应用层下的DeviceIoControl
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOManager; //DeviceIoControl()

	//设置通信方式--直接方式I/O
	DeviceObject->Flags |= DO_BUFFERED_IO;
	//设置文件字对齐
	DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;

	//设备初始化完成能够工作了
	DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

	//提示驱动载入成功
	DbgPrint("Hello Driver !\r\n");

	return STATUS_SUCCESS;
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

2.Ring3应用层代码的编写:

//Ring3.cpp
#include <windows.h>
#include <stdio.h>

//包括控制码的头文件
#include "..\Ring0\codemsg.h"

//向驱动发送请求
BOOL CallDriver(char *ID,char *lpBuffer)
{
	HANDLE service = 0;
	HANDLE device = 0;
	char ret[1024];
	WCHAR ToSend[512];
	DWORD code = -1;
	DWORD bytes;

	//通过符号连接打开设备对象
	device = CreateFile("\\\\.\\www.AntiGameProtect.com", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
	if( !device || device==INVALID_HANDLE_VALUE )
	{
		printf("打开驱动失败,驱动载入不成功. %d\r\n",GetLastError());
		return FALSE;
	}

	//推断输入的命令是否是"-file"
	if(!strcmp(ID,"-file"))
	{
		//相应我们驱动以下的控制码。

code = INIT_FILE_NAME;
	}

	//推断驱动的控制码是否有效
	if (code == -1)
	{
		printf("无效的ID\r\n");
		return FALSE;
	}

	//将ascii码lpBuffer字符串转unicode码字符串ToSend
	MultiByteToWideChar(CP_ACP, 0, lpBuffer, -1, ToSend, sizeof(ToSend));

	DeviceIoControl(device,
		CODEMSG(code),         //驱动的控制码
		ToSend,                //输入缓冲区
		(wcslen(ToSend)+1)*2,  //输入缓冲区的大小
		&ret,                  //输出缓冲区
		sizeof(ret),           //输出缓冲区的大小
		&bytes,                //返回的字节数
		NULL);

	//关闭驱动文件
	CloseHandle(device);

	printf("完毕!\r\n");

	return TRUE;
}

//main函数
void main(int argc,char *argv[])
{
	//推断用户输入的合法性
	if (argc != 3)
	{
		printf("Example:%s ID CommandLine\r\n",argv[0]);
		return;
	}

	//调用驱动的代码
	CallDriver(argv[1], argv[2]);

	return;
}

版权声明:本文博主原创文章。博客,未经同意不得转载。

时间: 2024-10-31 10:06:08

例子驱动通信基础架构的相关文章

领域驱动设计架构风格

领域驱动设计 (DDD) 是面向对象的软件设计方法,基于业务领域.元素和行为,以及它们之间的关系.其目标是将潜在业务领域的实现用业务领域专家语言定义的领域模型来表达出来.领域模型可以看一个框架,让业务变得有条理的解决方案. 要应用领域驱动设计,您必须对您想建模的业务领域有很了解, 或者熟练掌握这些业务知识.开发团队将经常与业务领域专家合作来创建模型.架构师,开发人员和主题专家有着不同的背景,在许多环境中将使用不同的语言来描述他们的目标,设计和要求. 而在域驱动设计中,整个团队统一使用一种专注于业

tornado项目之基于领域驱动模型架构设计的京东用户管理后台

本博文将一步步揭秘京东等大型网站的领域驱动模型,致力于让读者完全掌握这种网络架构中的“高富帅”. 一.预备知识: 1.接口: python中并没有类似java等其它语言中的接口类型,但是python中有抽象类和抽象方法.如果一个抽象类有抽象方法,那么继承它的子类必须实现抽象类的所有方法,因此,我们基于python的抽象类和抽象方法实现接口功能. 示例代码: from abc import ABCMeta from abc import abstractmethod #导入抽象方法 class F

网卡驱动设计---架构分析加回环网卡驱动设计(网卡驱动上)

网卡驱动架构分析: 1. Linux网络子系统 2. 重要数据结构 总结一下三个重要的数据结构: 2.1. net_device 2.2. net_device_ops 2.3. sk_buff 3. 网卡驱动架构分析 CS8900.c //早期2410使用的网卡芯片 3.1. 网卡初始化 首先找到驱动程序的入口: 早期的驱动入口并不是module_init()函数,而是init_module,所以找到这个函数 int __init init_module(void) { struct net_

通过例子理解 k8s 架构 - 每天5分钟玩转 Docker 容器技术(122)

为了帮助大家更好地理解 Kubernetes 架构,我们部署一个应用来演示各个组件之间是如何协作的. 执行命令 kubectl run httpd-app --image=httpd --replicas=2 等待一段时间,应用部署完成. Kubernetes 部署了 deployment httpd-app,有两个副本 Pod,分别运行在 k8s-node1 和 k8s-node2. 详细讨论整个部署过程. ① kubectl 发送部署请求到 API Server. ② API Server

领域驱动设计的面向服务架构

[.NET领域驱动设计实战系列]专题二:结合领域驱动设计的面向服务架构来搭建网上书店 一.前言 在前面专题一中,我已经介绍了我写这系列文章的初衷了.由于dax.net中的DDD框架和Byteart Retail案例并没有对其形成过程做一步步分析,而是把整个DDD的实现案例展现给我们,这对于一些刚刚接触领域驱动设计的朋友可能会非常迷茫,从而觉得领域驱动设计很难,很复杂,因为学习中要消化一个整个案例的知识,这样未免很多人消化不了就打退堂鼓,就不继续研究下去了,所以这样也不利于DDD的推广.然而本系列

[.NET领域驱动设计实战系列]专题二:结合领域驱动设计的面向服务架构来搭建网上书店

一.前言 在前面专题一中,我已经介绍了我写这系列文章的初衷了.由于dax.net中的DDD框架和Byteart Retail案例并没有对其形成过程做一步步分析,而是把整个DDD的实现案例展现给我们,这对于一些刚刚接触领域驱动设计的朋友可能会非常迷茫,从而觉得领域驱动设计很难,很复杂,因为学习中要消化一个整个案例的知识,这样未免很多人消化不了就打退堂鼓,就不继续研究下去了,所以这样也不利于DDD的推广.然而本系列可以说是刚接触领域驱动设计朋友的福音,本系列将结合领域驱动设计的思想来一步步构建一个网

块设备驱动架构分析

1. 块设备概念:块设备是指只能以块为单位进行访问的设备,块的大小一般是512个字节的整数倍.常见的块设备包括硬件,SD卡,光盘等.</span> 上边是通过一个编写好的块设备驱动,然后安装块设备驱动以及一些相关操作来体会块设备驱动!(此处省略) 2. 块设备驱动的系统架构 2.1 系统架构---VFS VFS是对各种具体文件系统的一种封装,用户程序访问文件提供统一的接口. 2.2 系统架构---Cache 当用户发起文件访问请求的时候,首先回到Disk Cache中寻址文件是否被缓存了,如果

我所看到的视频采集前端vfe和camera,decode等交互的驱动架构

到目前为止接触的处理器也多了,比较深入的驱动主要是视频采集前端,包括TI的DM64xx,DM3730,全志的A31等.发现所其所采用的框架基本不一样. 当然典型的camera如ov系列,decode如tvp系列等都是作为一个i2c_client存在的,这个驱动的架构大致都类似. 在这里姑且将采集前端称为vpfe: 1.如dm3730的内核2.6.32版本中,其采用master和slave的驱动架构,来进行attrach操作的.这就使得vpfe和camera的架构需要以v4l2_int_devic

【系统架构理论】一篇文章搞掂:领域驱动设计

一.什么是领域驱动设计 1.1.面向业务的设计 当我们需要构建一个业务复杂的系统,我们不仅要从技术角度去构建一个稳健的系统,还要从业务角度出发,保证系统能满足业务需求. 架构设计的考虑点:不仅面向技术,更应该面向业务:面对不同的业务复杂度,选择的架构可能不同. 架构师的工作:面对复杂的业务逻辑,需要整合业务和技术才能很好地解决.业务架构驱动技术架构. 一个典型开发团队:新手.中级开发者.高级开发者/架构师(技术架构).领域专家/产品经理(业务架构).项目经理 要解决的问题:将复杂的业务架构梳理好