驅動程式與應用程式的通信離不開派遣函數,派遣函數是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;
}