天天看點

驅動開發:驅動與應用的簡單通信

驅動程式與應用程式的通信離不開派遣函數,派遣函數是Windows驅動程式設計中的重要概念,一般情況下驅動程式負責處理I/O特權請求,而大部分IO的處理請求是在派遣函數中處理的,當使用者請求資料時,作業系統會提前處理好請求,并将其派遣到指定的核心函數中執行,接下來将詳細說明派遣函數的使用并通過派遣函數讀取Shadow SSDT中的内容。

先來簡單介紹一下 ​

​IRP(I/O Request Package)​

​ 輸入輸出請求包,該請求包在Windows核心中是一個非常重要的資料結構,當我們的上層應用與底層的驅動程式通信時,應用程式就會發出I/O請求,作業系統将該請求轉化為相應的IRP資料,然後會根據不同的請求資料将請求派遣到相應的驅動函數中執行,這一點有點類似于Windows的消息機制。

簡單的驅動通信: 注冊兩個派遣函數,當裝置建立的時候觸發,以及關閉時觸發。

#include <ntddk.h>

VOID UnDriver(PDRIVER_OBJECT pDriver)
{
  PDEVICE_OBJECT pDev;         // 用來取得要删除裝置對象
  UNICODE_STRING SymLinkName;  // 局部變量symLinkName

  pDev = pDriver->DeviceObject;
  IoDeleteDevice(pDev);                                       // 調用IoDeleteDevice用于删除裝置
  RtlInitUnicodeString(&SymLinkName, L"\\??\\My_Driver");   // 初始化字元串将symLinkName定義成需要删除的符号連結名稱
  IoDeleteSymbolicLink(&SymLinkName);                         // 調用IoDeleteSymbolicLink删除符号連結
  DbgPrint("删除裝置與符号連結成功...");
}

NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
  pIrp->IoStatus.Status = STATUS_SUCCESS;          // 傳回成功
  DbgPrint("派遣函數 IRP_MJ_CREATE 成功執行 !\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 成功執行 !\n");
  IoCompleteRequest(pIrp, IO_NO_INCREMENT);        // 訓示完成此IRP
  return STATUS_SUCCESS;                           // 傳回成功

}

NTSTATUS CreateDriverObject(IN PDRIVER_OBJECT pDriver)
{
  NTSTATUS Status;
  PDEVICE_OBJECT pDevObj;
  UNICODE_STRING DriverName;
  UNICODE_STRING SymLinkName;

  RtlInitUnicodeString(&DriverName, L"\\Device\\My_Device");
  Status = IoCreateDevice(pDriver, 0, &DriverName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj);
  DbgPrint("指令 IoCreateDevice 狀态: %d", Status);

  // DO_BUFFERED_IO 設定讀寫方式 Flags的三個不同的值分别為:DO_BUFFERED_IO、DO_DIRECT_IO和0
  pDevObj->Flags |= DO_BUFFERED_IO;
  RtlInitUnicodeString(&SymLinkName, L"\\??\\My_Device");
  Status = IoCreateSymbolicLink(&SymLinkName, &DriverName);
  DbgPrint("目前指令IoCreateSymbolicLink狀态: %d", Status);
  return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath)
{
  CreateDriverObject(pDriver);           // 調用建立裝置子過程
  // 注冊兩個派遣函數,分别對應建立與關閉,派遣函數名可自定義
  pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;    // 建立成功派遣函數
  pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;      // 關閉派遣函數

  DbgPrint("驅動加載完成...");
  pDriver->DriverUnload = UnDriver;
  return STATUS_SUCCESS;
}      
#include <windows.h>
#include <stdio.h>
#include <winioctl.h>

int main()
{
  HANDLE hDevice = CreateFile(L"\\\\.\\My_Device", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hDevice == INVALID_HANDLE_VALUE) //判斷hDevice傳回值是否為空
  {
    printf("擷取驅動句柄失敗!錯誤: %d\n", GetLastError());
    getchar();
  }

  getchar();
  CloseHandle(hDevice);
  return 0;
}      
#include <ntddk.h>

VOID UnDriver(PDRIVER_OBJECT pDriver)
{
  PDEVICE_OBJECT pDev;         // 用來取得要删除裝置對象
  UNICODE_STRING SymLinkName;  // 局部變量symLinkName
  pDev = pDriver->DeviceObject;
  IoDeleteDevice(pDev);                                       // 調用IoDeleteDevice用于删除裝置
  RtlInitUnicodeString(&SymLinkName, L"\\??\\My_Driver");     // 初始化字元串将symLinkName定義成需要删除的符号連結名稱
  IoDeleteSymbolicLink(&SymLinkName);                         // 調用IoDeleteSymbolicLink删除符号連結
  DbgPrint("删除裝置與符号連結成功...");
}
NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
  pIrp->IoStatus.Status = STATUS_SUCCESS;          // 傳回成功
  DbgPrint("派遣函數 IRP_MJ_CREATE 成功執行 !\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 成功執行 !\n");
  IoCompleteRequest(pIrp, IO_NO_INCREMENT);        // 訓示完成此IRP
  return STATUS_SUCCESS;                           // 傳回成功
}

NTSTATUS DispatchRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
  NTSTATUS Status = STATUS_SUCCESS;
  PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(pIrp);
  ULONG ulReadLength = Stack->Parameters.Read.Length;
  pIrp->IoStatus.Status = Status;
  pIrp->IoStatus.Information = ulReadLength;
  DbgPrint("應用要讀取的長度:%d\n", ulReadLength);

  // 将核心中的緩沖區全部填充為0x68 友善示範讀取的效果
  memset(pIrp->AssociatedIrp.SystemBuffer, 0x68, ulReadLength);
  IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  return Status;
}

NTSTATUS CreateDriverObject(IN PDRIVER_OBJECT pDriver)
{
  NTSTATUS Status;
  PDEVICE_OBJECT pDevObj;
  UNICODE_STRING DriverName;
  UNICODE_STRING SymLinkName;

  RtlInitUnicodeString(&DriverName, L"\\Device\\My_Device");
  Status = IoCreateDevice(pDriver, 0, &DriverName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj);
  DbgPrint("指令 IoCreateDevice 狀态: %d", Status);
  pDevObj->Flags |= DO_BUFFERED_IO;
  RtlInitUnicodeString(&SymLinkName, L"\\??\\My_Device");
  Status = IoCreateSymbolicLink(&SymLinkName, &DriverName);
  DbgPrint("目前指令IoCreateSymbolicLink狀态: %d", Status);
  return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath)
{
  CreateDriverObject(pDriver);                               // 調用建立裝置
  pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;    // 建立成功派遣函數
  pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;      // 關閉派遣函數
  pDriver->MajorFunction[IRP_MJ_READ] = DispatchRead;

  DbgPrint("驅動加載完成...");
  pDriver->DriverUnload = UnDriver;
  return STATUS_SUCCESS;
}      
#include <windows.h>
#include <stdio.h>
#include <winioctl.h>

int main()
{
  HANDLE hDevice = CreateFile(L"\\\\.\\My_Device", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hDevice == INVALID_HANDLE_VALUE)
  {
    printf("擷取驅動句柄失敗: %d\n", GetLastError());
    getchar();
  }

  UCHAR buffer[10];
  ULONG ulRead;

  ReadFile(hDevice, buffer, 10, &ulRead, 0);
  for (int i = 0; i < (int)ulRead; i++)
  {
    printf("%02X", buffer[i]);
  }
  getchar();
  CloseHandle(hDevice);
  return 0;
}