驱动通信基本框架的实例

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_DIRECT_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;
}
时间: 2025-01-07 10:14:40

驱动通信基本框架的实例的相关文章

ssh框架整合实例

MyEclipse开发SSH(Struts+Spring+Hibernate)入门 Spring技术   2009-02-03 15:59   阅读328   评论0 字号: 大大  中中  小小 2008-01-31 01:31 (本文参考自 oksonic 的"Struts+Spring+Hibernate练习(完整)") 源码下载:http://ishare.iask.sina.com.cn/cgi-bin/fileid.cgi?fileid=2857703 注意:这个实例要加入

js实现的运动框架代码实例

js实现的运动框架代码实例:元素的运动效果在大量的场景中都有应用,最典型的一个就是网站的客服系统,一般都会随着滚动条运动,本章节就介绍一下js的一个运动框架实例,希望能够给需要的朋友带来借鉴作用.代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="author" content="http://www.softwh

spring MVC3原理教程及其框架搭建实例

原文:spring MVC3原理教程及其框架搭建实例 http://www.zuidaima.com/share/1816340522191872.htm 一.前言: 大家好,Spring3 MVC是非常优秀的MVC框架,由其是在3.0版本发布后,现在有越来越多的团队选择了Spring3 MVC了.Spring3 MVC结构简单,应了那句话简单就是美,而且他强大不失灵活,性能也很优秀. 官方的下载网址是:http://www.springsource.org/download   (本文使用是的

spring mvc+ibatis+mysql的组合框架入门实例demo源码下载

原文:spring mvc+ibatis+mysql的组合框架入门实例demo源码下载 源代码下载地址:http://www.zuidaima.com/share/1550463678958592.htm spring mvc+ibatis+mysql的组合框架实例 首页 http://localhost:端口/项目/index.jsp 添加用户 添加地址 项目截图 jar包截图

python之高性能网络编程并发框架eventlet实例

http://blog.csdn.net/mingzznet/article/details/38388299 前言: 虽然 eventlet 封装成了非常类似标准线程库的形式,但线程和eventlet在实际并发执行流程仍然有明显区别.在没有出现 I/O 阻塞时,除非显式声明,否则当前正在执行的 eventlet 永远不会把 cpu 交给其他的 eventlet,而标准线程则是无论是否出现阻塞,总是由所有线程一起争夺运行资源.所有 eventlet 对 I/O 阻塞无关的大运算量耗时操作基本没有

SSM框架-SpringMVC 实例文件上传下载

SSM框架-SpringMVC 实例文件上传下载 2017-04-17 09:38 4497人阅读 评论(6) 收藏 举报  分类: java基础(3)  目录(?)[+] 目录(?)[+] 林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文详细讲解了SpringMVC实例单文件上传.多文件上传.文件列表显示.文件下载. 本文工程免费下载 一.新建一个Web工程,导入相关的包 springmvc的包+commons-fileupload

linux块设备驱动---概念与框架(转)

基本概念   块设备(blockdevice) --- 是一种具有一定结构的随机存取设备,对这种设备的读写是按块进行的,他使用缓冲区来存放暂时的数据,待条件成熟后,从缓存一次性写入设备或者从设备一次性读到缓冲区. 字符设备(Character device) ---是一个顺序的数据流设备,对这种设备的读写是按字符进行的,而且这些字符是连续地形成一个数据流.他不具备缓冲区,所以对这种设备的读写是实时的. 扇区(Sectors):任何块设备硬件对数据处理的基本单位.通常,1个扇区的大小为512byt

Android网络请求框架AsyncHttpClient实例详解(配合JSON解析调用接口)

最近做项目要求使用到网络,想来想去选择了AsyncHttpClient框架开进行APP开发.在这里把我工作期间遇到的问题以及对AsyncHttpClient的使用经验做出相应总结,希望能对您的学习有所帮助. 首先按照惯例先来简单了解一些AsyncHttpClient网络框架的一些知识. 1.简介 Android中网络请求一般使用Apache HTTP Client或者采用HttpURLConnect,但是直接使用这两个类库需要写大量的代码才能完成网络post和get请求,而使用android-a

java框架----&gt;spring框架----&gt;使用实例

相关教程:1)spring官网相关实例 这是spring官网,该网址列举了spring框架的若干使用实例,如