一个实现了DeviceIoControl的KDM驱动程序
acmilan2016/06/27软件综合 IP:四川

警告:一定要在VMWare Workstation、VirtualBox等虚拟机中测试,不要在工作用机中加载编译的驱动程序

内核模式驱动程序非常危险,可能造成蓝屏死机,重要数据损坏丢失,Windows系统损坏,甚至硬件烧毁等严重后果

编译这个驱动需要安装DDK或WDK,编译方法是打开DDK或WDK命令提示,然后cd切换到所在目录执行build命令。

MAKEFILE

从DDK或WDK自带的示例中复制一个即可

SOURCES

<code class="language-makefile">TARGETNAME=mydrv1
TARGETTYPE=DRIVER
TARGETPATH=OBJ

INCLUDES=$(BASEDIR)\inc;\
	$(BASEDIR)\inc\ddk

SOURCES=mydrv1.cpp
</code>

头文件

<code class="language-cpp">#pragma once

#ifdef __cplusplus
extern "C" {
#endif

// 包含头文件
#include <ntddk.h>
//#include <wdm.h>

#ifdef __cplusplus
}
#endif

// 代码段定义
#define PAGEDCODE code_seg("PAGE") // 分页代码段(IRQL<=apc_level) #define lockedcode code_seg() 锁定代码段 initcode code_seg("init") 初始化代码段(初始化结束就卸载) 数据段定义 pageddata data_seg("page") 分页数据段(irql<="APC_LEVEL)" lockeddata data_seg() 锁定数据段 initdata data_seg("init") 初始化数据段(初始化结束就卸载) 获取数组大小 arraysize(p) (sizeof(p) sizeof((p)[0])) 自定义的设备附加数据 typedef struct _device_extension { pdevice_object pdevice; 指向当前设备对象 unicode_string ustrdevicename; 设备对象名称 ustrsymlinkname; 设备链接名称 } device_extension, *pdevice_extension; 函数声明 创建设备 ntstatus createdevice(in pdriver_object pdriverobject); 驱动卸载函数 void helloddkunload(in 默认分发函数 defdispatchroutine(pdevice_object pdevobj, pirp pirp); deviceiocontorl分发函数 ioctldispatchroutine(in deviceiocontrol控制码(未知设备,控制码0x800,缓冲的,任何访问权限) ioctl1 ctl_code(file_device_unknown,0x800,method_buffered,file_any_access) < code></=apc_level)></wdm.h></ntddk.h></code>

CPP源文件

<code class="language-cpp">#include "mydrv1.h"

#pragma INITCODE

// 驱动程序入口点
extern "C" NTSTATUS DriverEntry(
			IN PDRIVER_OBJECT pDriverObject,
			IN PUNICODE_STRING pRegistryPath)
{
	NTSTATUS status;

	KdPrint(("Enter DriverEntry\n"));

	// 设定卸载函数和分发函数
	pDriverObject->DriverUnload = HelloDDKUnload;
	pDriverObject->MajorFunction[IRP_MJ_CREATE] = // CreateFile
	pDriverObject->MajorFunction[IRP_MJ_READ] = // ReadFile
	pDriverObject->MajorFunction[IRP_MJ_WRITE] = // WriteFile
	pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DefDispatchRoutine; // CloseHandle
	pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoctlDispatchRoutine; // DeviceIoControl

	// 创建设备
	status = CreateDevice(pDriverObject);

	KdPrint(("DriverEntry end\n"));

	return status;
}

#pragma INITCODE

// 创建设备
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject)
{
	NTSTATUS status;
	PDEVICE_OBJECT pDevObj;
	PDEVICE_EXTENSION pDevExt;

	KdPrint(("Enter CreateDevice\n"));

	// 初始化设备对象名(\Device\MyDDKDevice)
	UNICODE_STRING devName;
	RtlInitUnicodeString(&devName, L"\\Device\\MyDDKDevice");

	// 创建设备对象
	status = IoCreateDevice(pDriverObject, // 驱动对象
							sizeof (DEVICE_EXTENSION), // 设备附加数据大小
							&(UNICODE_STRING)devName, // 设备对象名称
							FILE_DEVICE_UNKNOWN, // 未知设备类别
							0, // 设备特征
							TRUE, // 独占设备
							&pDevObj); // 返回PDEVICE_OBJECT
	if (!NT_SUCCESS(status))
		return status; // 创建失败,结束操作

	// 设置进行缓冲的I/O
	pDevObj->Flags |= DO_BUFFERED_IO;
	
	// 设置设备附加数据
	pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
	pDevExt->pDevice = pDevObj;
	pDevExt->ustrDeviceName = devName;

	// 初始化设备链接名(\??\HelloDDK == \DosDevice\HelloDDK)
	// 在Win32中被映射为\\.\HelloDDK
	UNICODE_STRING symLinkName;
	RtlInitUnicodeString(&symLinkName, L"\\??\\HelloDDK");

	// 将设备链接名保存到设备附加数据
	pDevExt->ustrSymLinkName = symLinkName;
	
	// 创建设备链接
	status = IoCreateSymbolicLink(&symLinkName, &devName);
	if (!NT_SUCCESS(status)) // 创建失败
	{
		IoDeleteDevice(pDevObj); // 删除设备对象
		return status; // 结束操作
	}

	KdPrint(("CreateDevice end\n"));

	return STATUS_SUCCESS;
}

#pragma PAGEDCODE

// 卸载驱动程序
VOID HelloDDKUnload(IN PDRIVER_OBJECT pDriverObject)
{
	PAGED_CODE(); // 检验IRQL(Checked Build)

	KdPrint(("Enter DriverUnload\n"));

	// 查找驱动程序建立的所有设备对象并删除
	PDEVICE_OBJECT pNextObj;
	pNextObj = pDriverObject->DeviceObject;
	while (pNextObj != NULL)
	{
		// 获取设备附加数据(保存有符号链接名)
		PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
			pNextObj->DeviceExtension;
		// 删除符号链接
		UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
		IoDeleteSymbolicLink(&pLinkName);
		// 查找下一个设备对象
		pNextObj = pNextObj->NextDevice;
		// 删除当前设备对象
		IoDeleteDevice(pDevExt->pDevice);
	}
	
	KdPrint(("DriverUnload end\n"));
}

#pragma PAGEDCODE

// 默认分发函数
NTSTATUS DefDispatchRoutine(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	PAGED_CODE(); // 检查IRQL(Checked Build)

	KdPrint(("Enter DefDispatchRoutine\n"));

	// 成功完成I/O请求
	NTSTATUS status = STATUS_SUCCESS;
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = 0; // 处理0字节
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	
	KdPrint(("DefDispatchRoutine end\n"));
	
	return status;
}

// DeviceIoControl分发函数
NTSTATUS IoctlDispatchRoutine(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp)
{
	PAGED_CODE(); // 检查IRQL(Checked Build)

	KdPrint(("Enter IoctlDispatchRoutine\n"));

	NTSTATUS status = STATUS_SUCCESS;
	
	// 从I/O请求包中获取对应于当前驱动的I/O请求
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);

	// 获取DeviceIoControl相关信息
	ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength; // 输入缓冲区大小
	ULONG out_size = stack->Parameters.DeviceIoControl.OutputBufferLength; // 输出缓冲区大小
	ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; // 控制码
	char *buffer = (char*)pIrp->AssociatedIrp.SystemBuffer; // 系统复制的缓冲区(既输入又输出)
	
	ULONG retsize = 0;

	switch (code) // 分析控制码
	{
	case IOCTL1:
		KdPrint(("Get ioctl code 1\n"));
		if (out_size < in_size + 11 || in_size < 1)
		{
			status = STATUS_BUFFER_TOO_SMALL; // 缓冲区太小
			retsize = 0;
			break;
		}
		RtlMoveMemory(buffer + in_size - 1, " UPPER CASE", 12); // 追加字符串
		retsize = in_size + 11; // 增加11个字节
		break;
	default:
		status = STATUS_INVALID_VARIANT; // 非法控制码
		retsize = 0;
	}
	
	// 完成请求
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = retsize;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);

	KdPrint(("IoctlDispatchRoutine end\n"));
	
	return status;
}
</code>

[修改于 8年6个月前 - 2016/06/27 18:39:04]

来自:计算机科学 / 软件综合
1
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
acmilan 作者
8年6个月前 修改于 8年6个月前 IP:四川
822017

调用代码(调用之前,必须安装并启动,请参考此帖):

<code class="language-cpp">// drvopen.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <windows.h>
#include <winioctl.h>

// DeviceIoControl控制码(未知设备,控制码0x800,缓冲的,任何访问权限)
#define IOCTL1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)

int _tmain(int argc, _TCHAR* argv[])
{
	// 打开设备
	HANDLE hdev = CreateFile(
		TEXT("\\\\.\\HelloDDK"), // 设备链接名称
		GENERIC_READ|GENERIC_WRITE, // 读写权限
		0, // 不共享
		NULL, // 没有安全属性
		OPEN_EXISTING, // 打开已存在的文件
		FILE_ATTRIBUTE_NORMAL, // 默认属性
		NULL); // 没有模板文件

	if (hdev == INVALID_HANDLE_VALUE)
	{
		printf("open device failed\n");
		return 1;
	}
	else
	{
		printf("open device success %p\n", hdev);
	}

	char buf1[] = "lower case";
	char buf2[sizeof buf1 + 1024];
	DWORD bytesret;

	// 调用设备的DeviceIoControl请求
	printf("put %d bytes: %s\n", sizeof buf1, buf1);
	if (DeviceIoControl(hdev, IOCTL1, buf1, sizeof buf1, buf2, sizeof buf2, &bytesret, NULL))
	{
		printf("get %d bytes: %s\n", bytesret, buf2);
	}
	else
	{
		printf("DeviceIoControl failed\n");
	}

	// 关闭设备
	CloseHandle(hdev);

	return 0;
}
</winioctl.h></windows.h></code>

运行结果:

<code class="language-txt">open device success 00000038
put 11 bytes: lower case
get 22 bytes: lower case UPPER CASE
</code>
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,5年10个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}