創建驅動設備(打開、關閉、讀取。寫入)

驅動代碼

#include<ntddk.h>

#define SYM_NAME L"\\??\\MaoYu"

// 驅動對象卸載的處理函數(回調)
void unLoad(PDRIVER_OBJECT pDriverObject)
{
	// 如果驅動設備存在
	if (pDriverObject->DeviceObject)
	{
		// 刪除符號鏈接
		UNICODE_STRING symName;
		RtlInitUnicodeString(&symName, SYM_NAME);			// 初始化字符結構
		IoDeleteSymbolicLink(&symName);							// 刪除符號鏈接

		// 刪除驅動設備
		IoDeleteDevice(pDriverObject->DeviceObject);

		DbgPrint("刪除設備成功");									// 打印調式信息
	}

	// 打印驅動卸載成功消息
	DbgPrint("驅動卸載成功++++++++");
}

// IRP 請求 創建(回調)	 1.驅動設備	2.rip對象
NTSTATUS myCreate(PDEVICE_OBJECT pDveice, PIRP prip)
{
	DbgPrint("用戶 創建動作");

	// 將信息設置爲0
	prip->IoStatus.Information = 0L;

	// IRP的處理狀態
	{
		// 將請求設置爲成功
		prip->IoStatus.Status = STATUS_SUCCESS;

		//	指示已完成了IO請求 1.IRP指針  2.系統定義的CCHAR常數  
		IoCompleteRequest(prip, IO_NO_INCREMENT);
	}

	return STATUS_SUCCESS;
}

// IRP 請求 清除	(回調)	 1.驅動設備	2.rip對象
NTSTATUS myCleanUp(PDEVICE_OBJECT pDveice, PIRP prip)
{
	DbgPrint("用戶 清除動作");

	// 將信息設置爲0
	prip->IoStatus.Information = 0L;

	// IRP的處理狀態
	{
		// 將請求設置爲成功
		prip->IoStatus.Status = STATUS_SUCCESS;

		//	指示已完成了IO請求 1.IRP指針  2.系統定義的CCHAR常數  
		IoCompleteRequest(prip, IO_NO_INCREMENT);
	}

	return STATUS_SUCCESS;
}

// IRP 請求 關閉(回調)	 1.驅動設備	2.rip對象
NTSTATUS myClose(PDEVICE_OBJECT pDveice, PIRP prip)
{
	DbgPrint("用戶 關閉動作");

	// 將信息設置爲0
	prip->IoStatus.Information = 0L;

	// IRP的處理狀態
	{
		// 將請求設置爲成功
		prip->IoStatus.Status = STATUS_SUCCESS;

		//	指示已完成了IO請求 1.IRP指針  2.系統定義的CCHAR常數  
		IoCompleteRequest(prip, IO_NO_INCREMENT);
	}

	return STATUS_SUCCESS;
}

// IRP 請求 讀取(回調)	 1.驅動設備	2.rip對象
NTSTATUS myRead(PDEVICE_OBJECT pDveice, PIRP prip)
{
	DbgPrint("用戶 讀取動作");

	// 返回一個指向呼叫者的I / O棧位置指定IRP,返回一個IO棧位置的結構體指針
	PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(prip);

	// 拿到IRP要讀取的大小
	ULONG size = pStack->Parameters.Read.Length;

	// 處理IRP讀取動作
	{
		// 拿到IRP的緩衝區		SystemBuffer 指向系統空間緩衝區的指針 PVOID類型
		PVOID buffer = prip->AssociatedIrp.SystemBuffer;

		// 定義一個字符串
		const char* content = "我是大貓魚";

		// 計算字符串的長度
		size_t count = strlen(content);

		// 將數據寫入到 IRP 緩衝區
		RtlCopyMemory(buffer, content, strlen(content));

		// IRP的格式信息 賦值爲寫入的長度
		prip->IoStatus.Information = count;
	}

	// IRP結果的處理狀態
	{
		// 將請求設置爲成功
		prip->IoStatus.Status = STATUS_SUCCESS;

		//	指示已完成了IO請求 1.IRP指針  2.系統定義的CCHAR常數  
		IoCompleteRequest(prip, IO_NO_INCREMENT);
	}

	return STATUS_SUCCESS;
}


// IRP 請求 寫入(回調)	 1.驅動設備	2.rip對象
NTSTATUS myWrite(PDEVICE_OBJECT pDveice, PIRP prip)
{
	DbgPrint("用戶 寫入動作");

	// 返回一個指向呼叫者的I / O棧位置指定IRP,返回一個IO棧位置的結構體指針
	PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(prip);

	// 拿到IRP要寫入的大小
	ULONG size = pStack->Parameters.Write.Length;

	// 拿到IRP的緩衝區		SystemBuffer 指向系統空間緩衝區的指針 PVOID類型
	PVOID buffer = prip->AssociatedIrp.SystemBuffer;

	// 處理IRP請求
	{
		// 將IRP緩衝區的內容拷貝到設備擴展字節緩衝區
		RtlCopyMemory(pDveice->DeviceExtension, buffer, size);

		// IRP的格式信息 賦值爲寫入的長度
		prip->IoStatus.Information = size;

		// 打印調式信息
		DbgPrint("IRP:%s", (PCHAR)pDveice->DeviceExtension);
	}

	// IRP結果的處理狀態
	{
		// 將請求設置爲成功
		prip->IoStatus.Status = STATUS_SUCCESS;

		//	指示已完成了IO請求 1.IRP指針  2.系統定義的CCHAR常數  
		IoCompleteRequest(prip, IO_NO_INCREMENT);
	}
	
	return STATUS_SUCCESS;
}

// 驅動入口函數	1.驅動對象指針		2.路徑的對象指針
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{

	// 設置驅動對象卸載回調以及打印調式信息
	{
		// 設置驅動對象的卸載函數
		pDriverObject->DriverUnload = unLoad;

		// 打印驅動加載成功消息
		DbgPrint("驅動加載:%wS", pRegPath->Buffer);
	}

	// 驅動的名稱
	UNICODE_STRING deviceName;

	// 驅動設備對象指針
	PDEVICE_OBJECT pDevice = NULL;

	// 創建驅動設備
	{
		// 初始化Unicode字符串的計數器
		RtlInitUnicodeString(&deviceName, L"\\Device\\MaoYu");

		// 創建一個驅動程序使用的設備對象。
		NTSTATUS  status = IoCreateDevice(
			pDriverObject,							// 驅動對象地址
			1024L,									// 設備擴展的字節數大小
			&deviceName,							// 驅動設備的名稱
			FILE_DEVICE_UNKNOWN,			// 未知的設備
			0L,											// 有關設備的其它信息
			TRUE,										// 是否代表專業對象
			&pDevice);									// 驅動設備的指針

		// 如果驅動設備創建失敗
		if (status != STATUS_SUCCESS)
		{
			DbgPrint("創建驅動設備失敗");		// 打印錯誤信息
			return status;
		}
	}

	// 創建對外的符號鏈接
	{

		UNICODE_STRING symName;			// 設備符號鏈接

		// 初始化設備符號字符結構
		RtlInitUnicodeString(&symName, SYM_NAME);

		// 創建符號鏈接  1.符號鏈接的字符結構 2.驅動設備的名稱
		NTSTATUS status = IoCreateSymbolicLink(&symName, &deviceName);

		if (status != STATUS_SUCCESS)
		{
			DbgPrint("創建符號鏈接失敗");		// 打印錯誤信息			
			IoDeleteDevice(pDevice);			// 刪除設備
			return status;
		}
	}


	// 設置 驅動對象的標誌類型 通過緩衝區進行 IO處理,注意要進行按位 或運算
	pDevice->Flags |= DO_BUFFERED_IO;

	// 處理IRP請求
	{
		// IRP創建動作
		pDriverObject->MajorFunction[IRP_MJ_CREATE] = myCreate;

		// IRP清除動作
		pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = myCleanUp;

		// IRP關閉動作
		pDriverObject->MajorFunction[IRP_MJ_CLOSE] = myClose;

		// IRP讀取動作
		pDriverObject->MajorFunction[IRP_MJ_READ] = myRead;

		// IRP寫入動作
		pDriverObject->MajorFunction[IRP_MJ_WRITE] = myWrite;
	}



	return STATUS_SUCCESS;
}

c++代碼

#include<iostream>
#include<string>
#include<Windows.h>

int main(const int argc, const char** argv)
{

	HANDLE hFile = NULL;

	hFile = ::CreateFileW(
		L"\\\\.\\MaoYu",
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		std::cout << "設備打開失敗" << std::endl;
		system("pause");
		return 1;
	}
	else
	{
		std::cout << "設備打開成功" << std::endl;
	}

	system("pause");

	// 讀取
	{
		PCHAR buffer[1024]{ 0 };

		if (::ReadFile(hFile, buffer, sizeof(buffer), NULL, NULL))
		{
			printf("%s", buffer);
		}
		else
		{
			std::cout << "讀取錯誤" << std::endl;
			system("pause");
			::CloseHandle(hFile);
			return 1;
		}
		system("pause");
	}

		// 寫入
	{
		std::string str = "hello word";

		if (::WriteFile(hFile, str.c_str(), str.length(), NULL, NULL))
		{
			std::cout << "寫入成功" << std::endl;
		}
		else
		{
			std::cout << "寫入失敗" << std::endl;
		}
	}
	system("pause");
	::CloseHandle(hFile);
}

這簡單的實例,簡單的流程解釋
// 驅動端
1.創建一個驅動設備
2.創建這個設備的外部符號鏈接
3.設置這個設備的通信標誌(Flags)
4.設置IRP請求的回調函數

// 用戶端
1.打開一個設備
2.讀取設備的數據
3.寫入數據到設備

它們直接的交互,則是通過一個緩衝區。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章