欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言驅動開發(fā)之通過ReadFile與內核層通信

 更新時間:2022年09月30日 16:32:37   作者:lyshark  
驅動與應用程序的通信是非常有必要的,內核中執(zhí)行代碼后需要將其動態(tài)顯示給應用層。為了實現內核與應用層數據交互則必須有通信的方法,微軟為我們提供了三種通信方式,本文先來介紹通過ReadFile系列函數實現的通信模式

驅動與應用程序的通信是非常有必要的,內核中執(zhí)行代碼后需要將其動態(tài)顯示給應用層,但驅動程序與應用層畢竟不在一個地址空間內,為了實現內核與應用層數據交互則必須有通信的方法,微軟為我們提供了三種通信方式,如下先來介紹通過ReadFile系列函數實現的通信模式。

長話短說,不說沒用的概念,首先系統(tǒng)中支持的通信模式可以總結為三種。

  • 緩沖區(qū)方式讀寫(DO_BUFFERED_IO)
  • 直接方式讀寫(DO_DIRECT_IO)
  • 其他方式讀寫

而通過ReadFile,WriteFile系列函數實現的通信機制則屬于緩沖區(qū)通信模式,在該模式下操作系統(tǒng)會將應用層中的數據復制到內核中,此時應用層調用ReadFile,WriteFile函數進行讀寫時,在驅動內會自動觸發(fā) IRP_MJ_READ 與 IRP_MJ_WRITE這兩個派遣函數,在派遣函數內則可以對收到的數據進行各類處理。

首先需要實現初始化各類派遣函數這么一個案例,如下代碼則是通用的一種初始化派遣函數的基本框架,分別處理了IRP_MJ_CREATE創(chuàng)建派遣,以及IRP_MJ_CLOSE關閉的派遣,此外函數DriverDefaultHandle的作用時初始化其他派遣用的,也就是將除去CREATE/CLOSE這兩個派遣之外,其他的全部賦值成初始值的意思,當然不增加此段代碼也是無妨,并不影響代碼的實際執(zhí)行。

#include <ntifs.h>

// 卸載驅動執(zhí)行
VOID UnDriver(PDRIVER_OBJECT pDriver)
{
	PDEVICE_OBJECT pDev;                                        // 用來取得要刪除設備對象
	UNICODE_STRING SymLinkName;                                 // 局部變量symLinkName
	pDev = pDriver->DeviceObject;
	IoDeleteDevice(pDev);                                           // 調用IoDeleteDevice用于刪除設備
	RtlInitUnicodeString(&SymLinkName, L"\\??\\LySharkDriver");     // 初始化字符串將symLinkName定義成需要刪除的符號鏈接名稱
	IoDeleteSymbolicLink(&SymLinkName);                             // 調用IoDeleteSymbolicLink刪除符號鏈接
	DbgPrint("驅動卸載完畢...");
}

// 創(chuàng)建設備連接
// LyShark.com
NTSTATUS CreateDriverObject(IN PDRIVER_OBJECT pDriver)
{
	NTSTATUS Status;
	PDEVICE_OBJECT pDevObj;
	UNICODE_STRING DriverName;
	UNICODE_STRING SymLinkName;

	// 創(chuàng)建設備名稱字符串
	RtlInitUnicodeString(&DriverName, L"\\Device\\LySharkDriver");
	Status = IoCreateDevice(pDriver, 0, &DriverName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj);

	// 指定通信方式為緩沖區(qū)
	pDevObj->Flags |= DO_BUFFERED_IO;

	// 創(chuàng)建符號鏈接
	RtlInitUnicodeString(&SymLinkName, L"\\??\\LySharkDriver");
	Status = IoCreateSymbolicLink(&SymLinkName, &DriverName);
	return STATUS_SUCCESS;
}

// 創(chuàng)建回調函數
NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	pIrp->IoStatus.Status = STATUS_SUCCESS;          // 返回成功
	DbgPrint("派遣函數 IRP_MJ_CREATE 執(zhí)行 \n");
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);        // 指示完成此IRP
	return STATUS_SUCCESS;                           // 返回成功
}

// 關閉回調函數
NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	pIrp->IoStatus.Status = STATUS_SUCCESS;          // 返回成功
	DbgPrint("派遣函數 IRP_MJ_CLOSE 執(zhí)行 \n");
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);        // 指示完成此IRP
	return STATUS_SUCCESS;                           // 返回成功
}

// 默認派遣函數
NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);

	return status;
}

// 入口函數
// By: LyShark
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("hello lyshark \n");

	// 調用創(chuàng)建設備
	CreateDriverObject(pDriver);

	pDriver->DriverUnload = UnDriver;                          // 卸載函數
	pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;    // 創(chuàng)建派遣函數
	pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;      // 關閉派遣函數

	// 初始化其他派遣
	for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
	{
		DbgPrint("初始化派遣: %d \n", i);
		pDriver->MajorFunction[i] = DriverDefaultHandle;
	}

	DbgPrint("驅動加載完成...");

	return STATUS_SUCCESS;
}

代碼運行效果如下:

通用框架有了,接下來就是讓該驅動支持使用ReadWrite的方式實現通信,首先我們需要在DriverEntry處增加兩個派遣處理函數的初始化。

// 入口函數
// By: LyShark
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("hello lyshark \n");

	// 調用創(chuàng)建設備
	CreateDriverObject(pDriver);

	// 初始化其他派遣
	for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
	{
		DbgPrint("初始化派遣: %d \n", i);
		pDriver->MajorFunction[i] = DriverDefaultHandle;
	}

	pDriver->DriverUnload = UnDriver;                          // 卸載函數
	pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;    // 創(chuàng)建派遣函數
	pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;      // 關閉派遣函數

	// 增加派遣處理
	pDriver->MajorFunction[IRP_MJ_READ] = DispatchRead;        // 讀取派遣函數
	pDriver->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;      // 寫入派遣函數

	DbgPrint("驅動加載完成...");

	return STATUS_SUCCESS;
}

接著,我們需要分別實現這兩個派遣處理函數,如下DispatchRead負責讀取時觸發(fā),與之對應DispatchWrite負責寫入觸發(fā)。

  • 引言:
  • 對于讀取請求I/O管理器分配一個與用戶模式的緩沖區(qū)大小相同的系統(tǒng)緩沖區(qū)SystemBuffer,當完成請求時I/O管理器將驅動程序已經提供的數據從系統(tǒng)緩沖區(qū)復制到用戶緩沖區(qū)。
  • 對于寫入請求,會分配一個系統(tǒng)緩沖區(qū)并將SystemBuffer設置為地址,用戶緩沖區(qū)的內容會被復制到系統(tǒng)緩沖區(qū),但是不設置UserBuffer緩沖。

通過IoGetCurrentIrpStackLocation(pIrp)接收讀寫請求長度,偏移等基本參數,AssociatedIrp.SystemBuffer則是讀寫緩沖區(qū),IoStatus.Information是輸出緩沖字節(jié)數,Parameters.Read.Length是讀取寫入的字節(jié)數。

// 讀取回調函數
NTSTATUS DispatchRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	NTSTATUS Status = STATUS_SUCCESS;
	PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(pIrp);
	ULONG ulReadLength = Stack->Parameters.Read.Length;

	char szBuf[128] = "hello lyshark";

	pIrp->IoStatus.Status = Status;
	pIrp->IoStatus.Information = ulReadLength;
	DbgPrint("讀取長度:%d \n", ulReadLength);

	// 取出字符串前5個字節(jié)返回給R3層
	memcpy(pIrp->AssociatedIrp.SystemBuffer, szBuf, ulReadLength);

	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return Status;
}

// 接收傳入回調函數
// By: LyShark
NTSTATUS DispatchWrite(struct _DEVICE_OBJECT *DeviceObject, struct _IRP *Irp)
{
	NTSTATUS Status = STATUS_SUCCESS;
	PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
	ULONG ulWriteLength = Stack->Parameters.Write.Length;
	PVOID ulWriteData = Irp->AssociatedIrp.SystemBuffer;

	// 輸出傳入字符串
	DbgPrint("傳入長度: %d 傳入數據: %s \n", ulWriteLength, ulWriteData);

	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return Status;
}

如上部分都是在講解驅動層面的讀寫派遣,應用層還沒有介紹,在應用層我們只需要調用ReadFile函數當調用該函數時驅動中會使用DispatchRead派遣例程來處理這個請求,同理調用WriteFile函數則觸發(fā)的是DispatchWrite派遣例程。

我們首先從內核中讀出前五個字節(jié)并放入緩沖區(qū)內,輸出該緩沖區(qū)內的數據,然后在調用寫入,將hello lyshark寫回到內核里里面,這段代碼可以這樣來寫。

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

int main(int argc, char *argv[])
{
  HANDLE hDevice = CreateFileA("\\\\.\\LySharkDriver", GENERIC_READ | GENERIC_WRITE, 0,
    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hDevice == INVALID_HANDLE_VALUE)
  {
    CloseHandle(hDevice);
    return 0;
  }

  // 從內核讀取數據到本地
  char buffer[128] = { 0 };
  ULONG length;

  // 讀入到buffer長度為5
  // By:lyshark.com
  ReadFile(hDevice, buffer, 5, &length, 0);
  for (int i = 0; i < (int)length; i++)
  {
    printf("讀取字節(jié): %c", buffer[i]);
  }

  // 寫入數據到內核
  char write_buffer[128] = "hello lyshark";
  ULONG write_length;
  WriteFile(hDevice, write_buffer, strlen(write_buffer), &write_length, 0);

  system("pause");
  CloseHandle(hDevice);
  return 0;
}

使用驅動工具安裝我們的驅動,然后運行該應用層程序,實現通信,效果如下所示:

到此這篇關于C語言驅動開發(fā)之通過ReadFile與內核層通信的文章就介紹到這了,更多相關C語言 ReadFile內核層通信內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C++多線程實現TCP服務器端同時和多個客戶端通信

    C++多線程實現TCP服務器端同時和多個客戶端通信

    通訊建立后首先由服務器端發(fā)送消息,客戶端接收消息;接著客戶端發(fā)送消息,服務器端接收消息,實現交互發(fā)送消息。本文主要介紹了C++多線程實現TCP服務器端同時和多個客戶端通信,感興趣的可以了解一下
    2021-05-05
  • C++中4種強制類型轉換的區(qū)別詳析

    C++中4種強制類型轉換的區(qū)別詳析

    這篇文章主要給大家介紹了關于C++中4種強制類型轉換區(qū)別的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • 關于C語言多線程pthread庫的相關函數說明

    關于C語言多線程pthread庫的相關函數說明

    下面小編就為大家?guī)硪黄P于C語言多線程pthread庫的相關函數說明。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • C語言超細致講解分支語句

    C語言超細致講解分支語句

    分支結構的執(zhí)行是依據一定的條件選擇執(zhí)行路徑,而不是嚴格按照語句出現的物理順序。分支結構的程序設計方法的關鍵在于構造合適的分支條件和分析程序流程,根據不同的程序流程選擇適當的分支語句
    2022-05-05
  • C++順序容器(vector、deque、list)的使用詳解

    C++順序容器(vector、deque、list)的使用詳解

    本文主要介紹了C++順序容器(vector、deque、list)的使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06
  • 使用C# 判斷給定大數是否為質數的詳解

    使用C# 判斷給定大數是否為質數的詳解

    本篇文章是對使用C#判斷給定大數是否為質數的方法進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • 你知道如何自定義sort函數中的比較函數

    你知道如何自定義sort函數中的比較函數

    這篇文章主要介紹了如何自定義sort函數中的比較函數,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Qt使用流處理XML文件的示例代碼

    Qt使用流處理XML文件的示例代碼

    XML(eXtensible?Markup?Language)是一種通用的文本格式,被廣泛運用于數據交換和數據存儲。本文主要來和大家聊聊如何使用?Qt?處理?XML?格式的文檔,需要的可以參考一下
    2023-02-02
  • c++利用stl set_difference對車輛進出區(qū)域進行判定

    c++利用stl set_difference對車輛進出區(qū)域進行判定

    這篇文章主要介紹了set_difference,用于求兩個集合的差集,結果集合中包含所有屬于第一個集合但不屬于第二個集合的元素,需要的朋友可以參考下
    2017-03-03
  • C++ STL入門教程(1) vector向量容器使用方法

    C++ STL入門教程(1) vector向量容器使用方法

    這篇文章主要為大家詳細介紹了C++ STL入門教程第一篇,vector向量容器使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08

最新評論