windows 驱动与内核调试 学习2

Posted 不会写代码的丝丽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了windows 驱动与内核调试 学习2相关的知识,希望对你有一定的参考价值。

前言

我们知道我们驱动存在的意义往往是用于驱动硬件,而一个硬件读写大多数操作系统都是为文件io。既然是文件那么必然涉及到文件打开,读写等。我们看看在内核驱动该如何实现这些逻辑操作。


//驱动被加载的时候会调用此函数
NTSTATUS
DriverEntry(
	_In_ struct _DRIVER_OBJECT* DriverObject,
	_In_ PUNICODE_STRING    RegistryPath
)

	//如果你没有用到参数需要告诉系统。
	UNREFERENCED_PARAMETER(RegistryPath);
	//打印信息
	DbgPrint("hello  drive loaded");
	//触发一个断点
	//DbgBreakPoint();
	//驱动卸载回调注册
	DriverObject->DriverUnload = myUnload;


	//设置一个驱动映射的文件名称,RtlInitUnicodeString是一个便捷创建内核UNICODE_STRING函数
	UNICODE_STRING ustrDevName;
	//使用工具函数创建一个名叫MytestDriver驱动文件
	RtlInitUnicodeString(&ustrDevName, L"\\\\Device\\\\MytestDriver");
	//用于保存创建结果
	PDEVICE_OBJECT  pDevObj = NULL;
	
	//IoCreateDevice用于创建一个DEVICE_OBJECT对象
	auto ret = IoCreateDevice(DriverObject, 0, &ustrDevName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevObj);


	if (NT_SUCCESS(ret))
	
	//
		DbgPrint("IoCreateDevice 成功 %p\\r\\n", ret);
	
	else 
		DbgPrint("IoCreateDevice 失败\\r\\n");
		return STATUS_FAIL_CHECK;
	

	//这里便是注册驱动文件读写相关回调
	//注册一个创建文件回调
	DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
	//注册文件关闭
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
	//读取
	DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
	//写入
	DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
	//控制相关 其实也可以使用写入代替 但是为了职责分明额外多一个回调
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchControl;

	return STATUS_SUCCESS;

当函数卸载的时候一定要记得删除驱动文件哦

//这个函数被注册用于驱动卸载调用
VOID myUnload(
	struct _DRIVER_OBJECT* DriverObject
) 
	UNREFERENCED_PARAMETER(DriverObject);

	DbgPrint("hello  drive unloaded");

	PDEVICE_OBJECT DeviceObject = DriverObject->DeviceObject;

	if (DriverObject->DeviceObject !=NULL)
	
		DbgPrint("驱动文件不为空执行删除");
		IoDeleteDevice(DeviceObject);
	



我们贴出完成相关代码


#include <Ntddk.h>

//这个函数被注册用于驱动卸载调用
VOID myUnload(
	struct _DRIVER_OBJECT* DriverObject
) 
	UNREFERENCED_PARAMETER(DriverObject);

	DbgPrint("hello  drive unloaded");

	PDEVICE_OBJECT DeviceObject = DriverObject->DeviceObject;

	if (DriverObject->DeviceObject !=NULL)
	
		DbgPrint("驱动文件不为空执行删除");
		IoDeleteDevice(DeviceObject);
	




NTSTATUS
DispatchCreate(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) 
	UNREFERENCED_PARAMETER(Irp);
	UNREFERENCED_PARAMETER(DeviceObject);
	return STATUS_SUCCESS;

NTSTATUS
DispatchClose(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) 
	UNREFERENCED_PARAMETER(Irp);
	UNREFERENCED_PARAMETER(DeviceObject);
	return STATUS_SUCCESS;


NTSTATUS
DispatchRead(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) 
	UNREFERENCED_PARAMETER(Irp);
	UNREFERENCED_PARAMETER(DeviceObject);
	return STATUS_SUCCESS;

NTSTATUS
DispatchWrite(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) 
	UNREFERENCED_PARAMETER(Irp);
	UNREFERENCED_PARAMETER(DeviceObject);
	return STATUS_SUCCESS;


NTSTATUS
DispatchControl(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) 
	UNREFERENCED_PARAMETER(Irp);
	UNREFERENCED_PARAMETER(DeviceObject);
	return STATUS_SUCCESS;



//驱动被加载的时候会调用此函数
NTSTATUS
DriverEntry(
	_In_ struct _DRIVER_OBJECT* DriverObject,
	_In_ PUNICODE_STRING    RegistryPath
)

	//如果你没有用到参数需要告诉系统。
	UNREFERENCED_PARAMETER(RegistryPath);
	//打印信息
	DbgPrint("hello  drive loaded");
	//触发一个断点
	//DbgBreakPoint();
	//驱动卸载回调注册
	DriverObject->DriverUnload = myUnload;


	DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
	DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
	DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchControl;


	UNICODE_STRING ustrDevName;
	RtlInitUnicodeString(&ustrDevName, L"\\\\Device\\\\MytestDriver");
	PDEVICE_OBJECT  pDevObj = NULL;
	auto ret = IoCreateDevice(DriverObject, 0, &ustrDevName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevObj);


	if (NT_SUCCESS(ret))
	
		DbgPrint("IoCreateDevice 成功 %p\\r\\n", ret);
	
	else 
		DbgPrint("IoCreateDevice 失败\\r\\n");
		return STATUS_FAIL_CHECK;
	


	return STATUS_SUCCESS;

我们利用工具将驱动文件进行加载

然后我们在利用winobj查看我们注册驱动文件


我们最后执行卸载操作。

上面的注册驱动文件不能在ring3 进行文件读写,如果你期望ring3也可以驱动需要额外注册一个另一个映射名(符号链接 )
相关代码如下

	UNICODE_STRING symbolDevName;
	RtlInitUnicodeString(&symbolDevName, L"\\\\DosDevices\\\\MytestDriver");
	ret = IoCreateSymbolicLink(&symbolDevName, &ustrDevName);
	if (NT_SUCCESS(ret))
	
		DbgPrint("IoCreateSymbolicLink 成功 \\r\\n");
	
	else 
		DbgPrint("IoCreateSymbolicLink 失败%d\\r\\n", ret);

		IoDeleteDevice(pDevObj);

		return STATUS_FAIL_CHECK;
	

同样我们加载驱动


再卸载的时候同样记得要删除。

#include <Ntddk.h>



//这个函数被注册用于驱动卸载调用
VOID myUnload(
	struct _DRIVER_OBJECT* DriverObject
) 
	UNREFERENCED_PARAMETER(DriverObject);

	DbgPrint("hello  drive unloaded");

	PDEVICE_OBJECT DeviceObject = DriverObject->DeviceObject;

	if (DriverObject->DeviceObject != NULL)
	
		DbgPrint("驱动文件不为空执行删除");
		IoDeleteDevice(DeviceObject);


		UNICODE_STRING symbolDevName;
		RtlInitUnicodeString(&symbolDevName, L"\\\\DosDevices\\\\MytestDriver");
		IoDeleteSymbolicLink(&symbolDevName);
	




//驱动被加载的时候会调用此函数
NTSTATUS
DriverEntry(
	_In_ struct _DRIVER_OBJECT* DriverObject,
	_In_ PUNICODE_STRING    RegistryPath
)

	//如果你没有用到参数需要告诉系统。
	UNREFERENCED_PARAMETER(RegistryPath);
	//打印信息
	DbgPrint("hello  drive loaded");
	//触发一个断点
	//DbgBreakPoint();
	//驱动卸载回调注册
	DriverObject->DriverUnload = myUnload;


	DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
	DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
	DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchControl;


	UNICODE_STRING ustrDevName;
	RtlInitUnicodeString(&ustrDevName, L"\\\\Device\\\\MytestDriver");
	PDEVICE_OBJECT  pDevObj = NULL;
	auto ret = IoCreateDevice(DriverObject, 0, &ustrDevName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevObj);




	if (NT_SUCCESS(ret))
	
		DbgPrint("IoCreateDevice 成功 \\r\\n");
	
	else 
		DbgPrint("IoCreateDevice 失败 %d\\r\\n", ret);
		return STATUS_FAIL_CHECK;
	


	UNICODE_STRING symbolDevName;
	RtlInitUnicodeString(&symbolDevName, L"\\\\DosDevices\\\\MytestDriver");
	ret = IoCreateSymbolicLink(&symbolDevName, &ustrDevName);
	if (NT_SUCCESS(ret))
	
		DbgPrint("IoCreateSymbolicLink 成功 \\r\\n");
	
	else 
		DbgPrint("IoCreateSymbolicLink 失败%d\\r\\n", ret);

		IoDeleteDevice(pDevObj);

		return STATUS_FAIL_CHECK;
	

	return STATUS_SUCCESS;

微软IRP设计

以下来自微软官方的一个设计架构图

具体可参阅
(2) End-User I/O Requests and File Objects

微软使用IRP设计用于应用层和驱动层传递数据,并且驱动可以进行继续分层处理(比如文件系统驱动 可能有多个驱动 1级驱动提供读写 2级别提供特定大小的缓存功能的读写)。

我们现在完善上文驱动读写操作

NTSTATUS
DispatchRead(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) 
	DbgPrint("DispatchRead");

	UNREFERENCED_PARAMETER(DeviceObject);

	//因为分层驱动的设计,所以需要从Irp获取当前层级的参数
	PIO_STACK_LOCATION	pIrp = IoGetCurrentIrpStackLocation(Irp);
	//上册指定缓存区长度
	ULONG nLength = pIrp->Parameters.Read.Length;

	DbgPrint("DispatchRead buffer:%s bytes:%d", Irp->UserBuffer, nLength);
	//拷贝缓冲区
	memcpy(Irp->UserBuffer,"helloread",10);
	
	//通知上册成功写入
	Irp->iostatus.Status = STATUS_SUCCESS;
	//通知上层写入的大小
	Irp->IoStatus.Information = 10;
	//回调给io处理器完成请求
	IoCompleteRequest(Irp, IO_NO_INCREMENT);


	return STATUS_SUCCESS;

其他读写操作类似就不再举例

#include <Ntddk.h>



//这个函数被注册用于驱动卸载调用
VOID myUnload(
	struct _DRIVER_OBJECT* DriverObject
) 
	UNREFERENCED_PARAMETER(DriverObject);

	DbgPrint("hello  drive unloaded");

	PDEVICE_OBJECT DeviceObject = DriverObject->DeviceObject;

	if (DriverObject->DeviceObject != NULL)
	
		DbgPrint("驱动文件不为空执行删除");
		IoDeleteDevice(DeviceObject);


		UNICODE_STRING symbolDevName;
		RtlInitUnicodeString(&symbolDevName, L"\\\\DosDevices\\\\MytestDriver");
		IoDeleteSymbolicLink(&symbolDevName);
	




NTSTATUS
DispatchCreate(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) 
	UNREFERENCED_PARAMETER(Irp);
	UNREFERENCED_PARAMETER(DeviceObject);
	DbgPrint("DispatchCreate");

	return STATUS_SUCCESS;

NTSTATUS
DispatchClose(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) 
	DbgPrint("DispatchClose");

	UNREFERENCED_PARAMETER(Irp);
	UNREFERENCED_PARAMETER(DeviceObject);
	return STATUS_SUCCESS;


NTSTATUS
DispatchRead(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) 
	DbgPrint("DispatchRead");

	UNREFERENCED_PARAMETER(DeviceObject);


	PIO_STACK_LOCATION	pIrp = IoGetCurrentIrpStackLocation(Irp);
	ULONG nLength = pIrp->Parameters.Read.Length;

	DbgPrint("DispatchRead buffer:%s bytes:%d", Irp->UserBuffer, nLength);
	memcpy(Irp->UserBuffer,"helloread",10);

	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 10;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);


	return STATUS_SUCCESS;

NTSTATUS
DispatchWrite(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) 
	DbgPrint("DispatchWrite");
	UNREFERENCED_PARAMETER(DeviceObject);


	PIO_STACK_LOCATION	pIrp = IoGetCurrentIrpStackLocation(Irp);
	ULONG nLength = pIrp->Parameters.Write.Length;

	DbgPrint("DispatchWrite buffer:%s bytes:%d", Irp->UserBuffer, nLength);

	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 6;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	return STATUS_SUCCESS;


NTSTATUS
DispatchControl(
	_In_ struct _DEVICE_OBJECT* DeviceObject,
	_Inout_ struct _IRP* Irp
) 
	DbgPrint("DispatchControl");

	UNREFERENCED_PARAMETER(Irp);
	UNREFERENCED_PARAMETER(DeviceObject);
	return STATUS_SUCCESS;



//驱动被加载的时候会调用此函数
NTSTATUS
DriverEntry(
	_In_ struct _DRIVER_OBJECT* DriverObject,
	_In_ PUNICODE_STRING    RegistryPath
)

	//如果你没有用到参数需要告诉系统。
	UNREFERENCED_PARAMETER(RegistryPath);
	//打印信息
	DbgPrint("hello  drive loaded");
	//触发一个断点
	//DbgBreakPoint();
	//驱动卸载回调注册
	DriverObject->DriverUnload = myUnload;


	DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
	DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
	DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchControl;


	UNICODE_STRING ustrDevName;
	RtlInitUnicodeString(&ustrDevName, L"\\\\Device\\\\MytestDriver");
	PDEVICE_OBJECT  pDevObj = NULL;
	auto ret = IoCreateDevice(DriverObject, 0, &ustrDevName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevObj);




	if (NT_SUCCESS(ret))
	
		DbgPrint("IoCreateDevice 成功 \\r\\n");
	
	else 
		DbgPrint("IoCreateDevice 失败 %d\\r\\n", ret);
		return STATUS_FAIL_CHECK;
	


	UNICODE_STRING symbolDevName;
	RtlInitUnicodeString(&symbolDevName, L"\\\\DosDevices\\\\MytestDriver");
	ret = IoCreateSymbolicLink(&symbolDevName, &ustrDevName);
	if (NT_SUCCESS(ret))
	
		DbgPrint("IoCreateSymbolicLink 成功 \\r\\n");
	
	else 
		DbgPrint("IoCreateSymbolicLink 失败%d\\r\\n", ret);

		IoDeleteDevice(pDevObj);

		return STATUS_FAIL_CHECK;
	

	return STATUS_SUCCESS;

最后写一个应用层代码进行读写

// InvotationDevApp.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<Windows.h>
#include<stdlib.h>
int main()

	std::cout << "Hello World!\\n";


	HANDLE hFile;
	hFile = CreateFile("\\\\\\\\\\?\\\\MytestDriver",
		GENERIC_WRITE | GENERIC_READ,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL
	);
	if (hFile == INVALID_HANDLE_VALUE)
	
		std::cout << "INVALID_HANDLE_VALUE  "<< GetLastError()<<"\\n";

		return EXIT_FAILURE;
	

	std::cout << "open ok\\n";
	DWORD dwBytes = 0;
	if (WriteFile(hFile, "hello", 6, &dwBytes, NULL))
	
		std::cout << "write ok " << dwBytes << std::endl;
	
	else 
		std::cout << "write failure " << dwBytes << std::endl;
	

	DWORD drBytes = 0;
	char szBuffer[120];
	if (ReadFile(hFile, szBuffer, sizeof szBuffer, &drBytes, NULL))
	
		std::cout << "read ok  " << drBytes << " "<< szBuffer << std::endl;
	
	else 
		std::cout << "read failure " << std::endl;
	


	CloseHandle(hFile);
	system("pause");
	return EXIT_SUCCESS;


reference

(1) a simple demo for WDM driver

(2) End-User I/O Requests and File Objects

以上是关于windows 驱动与内核调试 学习2的主要内容,如果未能解决你的问题,请参考以下文章

windows 驱动与内核调试 学习3

windows 驱动与内核调试 学习3

windows 驱动与内核调试 学习

windows 驱动与内核调试 学习

windows 驱动与内核调试 学习5

windows 驱动与内核调试 学习5