驅動開發
0環與3環的通信
設備對象
在之前開發窗口程序時,消息都是被封裝成一個結構體(MSG),在內核開發時,消息被封裝成另外一個結構體:IRP(I/O Request Package)
在窗口程序中,能夠接收消息的只能是窗口對象,在內核中,能夠接收IRP消息的只能是設備對象
創建設備對象
// 創建設備名稱
UNICODE_STRING deviceName;
RtlInitUnicodeString(&deviceName, L"\\Device\\MyDevice");/*
NTSTATUS IoCreateDevice([in] PDRIVER_OBJECT DriverObject, // 驅動對象[in] ULONG DeviceExtensionSize, // 指定要為設備對象的 設備擴展 分配的驅動程序確定字節數[in, optional] PUNICODE_STRING DeviceName, // 設備名稱[in] DEVICE_TYPE DeviceType, // 設備類型[in] ULONG DeviceCharacteristics, // 設備特征[in] BOOLEAN Exclusive, // 指定設備對象是否表示 獨占設備[out] PDEVICE_OBJECT *DeviceObject // 指向接收指向新創建的 DEVICE_OBJECT 結構的指針的變量的指針
);
*/// 創建設備對象
NTSTATUS ntIoCreate = IoCreateDevice(driverObject, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
數據的交互方式
// 設置數據的交互方式
driverObject->Flags |= DO_BUFFERED_IO;
- 緩存區方式讀寫(DO_BUFFERED_IO):操作系統將應用程序提供緩沖區的數據復制到內核模式下的地址中
- 直接方式讀寫(DO_DIRECT_IO):操作系統會將用戶模式下的緩沖區鎖住,然后操作系統將這段緩沖區在內核模式地址再次映射一遍,這樣,用戶模式的緩沖區和內核模式的緩沖區指向的是同一區域的物理內存(缺點就是要單獨占用物理頁面)
- 其他方式讀寫(在調用IoCreateDevice創建設備后對drivceObjcet->Flags既不設置DO_BUFFERED_IO也不設置DO_DIRECT_IO此時就是其它方式):在使用其他方式讀寫設備時,派遣函數直接讀寫應用程序提供的緩沖地址。在驅動程序中,直接操作應用程序的緩沖區是很危險的,只有驅動程序與應用程序運行在相同線程上下文的情況下,才能使用這種方式
IRP的類型
當應用層通過CreateFile,ReadFile,WriteFile,CloseHandle等函數打開,從設備讀取數據,向設備寫入數據,關閉設備的時候,會使操作系統系統產出不同的IRP_CREATE,IPR_MJ_READ,IRP_MJ_WRITE等IRP
其它類型
IRP類型 | 來源 |
---|---|
IRP_MJ_DEVICE_CONTROL | DeviceControl 函數會產生些IRP |
IRP_MJ_POWER | 在操作系統處理電源消息時,產生此IRP |
IRP_MJ_SHUTDOWN | 關閉系統前會產生些IRP |
IRP_MJ_DEVICE_CONTROL
才是我們Ring3與驅動交互的常規方式
測試代碼
3環應用程序代碼
#include<iostream>
#include<windows.h>#define IN_BUFFER_MAXLENGIT 0x10 // 輸入緩存最大長度
#define OUT_BUFFER_MAXLENGTH 0x10 // 輸出緩存最大長度
// 參數說明:1,設備類型,2,操作碼,3,以什么方式進行訪問,4,訪問權限
#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define SYMBOLICLINK_NAME "\\\\.\\MyTestDriver"HANDLE g_hDriver;BOOL open(const CHAR* pLinkName) {TCHAR szBuffer[10] = { 0 };g_hDriver = CreateFileA(pLinkName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);DWORD errorCode = GetLastError();swprintf(szBuffer,sizeof(szBuffer),L"%d:\n",errorCode);if (g_hDriver != INVALID_HANDLE_VALUE)return TRUE;else return FALSE;
}/*
BOOL DeviceIoControl([in] HANDLE hDevice, 設備句柄[in] DWORD dwIoControlCode, 控制代碼[in, optional] LPVOID lpInBuffer, 向0環傳遞的緩沖區的地址[in] DWORD nInBufferSize, 緩沖區的大小[out, optional] LPVOID lpOutBuffer, 向3還傳遞的緩沖區的地址[in] DWORD nOutBufferSize, 緩沖區的大小[out, optional] LPDWORD lpBytesReturned, 實際返回的長度(字節數)[in, out, optional] LPOVERLAPPED lpOverlapped
);
*/BOOL ioControl(DWORD dwIoCode,PVOID InBuffer,DWORD InBuffLen,PVOID OutBuff,DWORD OutBuffLen) { DWORD dw;DeviceIoControl(g_hDriver,dwIoCode,InBuffer,InBuffLen,OutBuff,OutBuffLen,&dw,NULL);return TRUE;
}int main() {DWORD dwInBuffer = 0x11112222;TCHAR szOutBuffer[OUT_BUFFER_MAXLENGTH] = { 0 };// 通過符號鏈接 打開設備if (open(SYMBOLICLINK_NAME)) {printf("open device success\n");}else {printf("open device failed\n");}ioControl(OPER2, &dwInBuffer, IN_BUFFER_MAXLENGIT, szOutBuffer, OUT_BUFFER_MAXLENGTH);CloseHandle(g_hDriver);system("pause");return 0;
}
0環驅動程序
#include <ntddk.h>#define DEVICE_NAME L"\\Device\\MyDevice"
// Ring3用CreateDevice打開設備時用 \\\\.\\MyTestDriver
#define SYMBOLICLINK_NAME L"\\??\\MyTestDriver"#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)// IRP_MJ_CREATE 處理函數
NTSTATUS IrpCreateProc(PDEVICE_OBJECT pDevObj,PIRP pIrp) {DbgPrint("設備創建了...");// 設置返回狀態pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// IRP_MJ_CLOSE 處理函數
NTSTATUS IrpCloseProc(PDEVICE_OBJECT pDevObj, PIRP pIrp) {DbgPrint("設備關閉了...");// 設置返回狀態pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;
}// IRP_MJ_DEVICE_CONTROL 處理函數
NTSTATUS IrpDeviceControlProc(PDEVICE_OBJECT pDevObj, PIRP pIrp) {NTSTATUS stauts = STATUS_INVALID_DEVICE_REQUEST;PIO_STACK_LOCATION pIrpStack;ULONG uIoControlCode;PVOID pIoBuffer;ULONG uInLength;ULONG uOutLength;ULONG uRead;ULONG uWrite;// 設置臨時變量的值uRead = 0;uWrite = 0x12345678;//獲取IRP數據pIrpStack = IoGetCurrentIrpStackLocation(pIrp);//獲取控制碼uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;// 獲取緩沖區地址(輸入和輸出的緩沖區都是一個)pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;// Ring3 發送數據的長度uInLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;// Ring0 發送數據的長度uOutLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;pIrp->IoStatus.Information = 0;switch (uIoControlCode) {case OPER1:{DbgPrint("調用IRP_MJ_DEVICE_CONTROL —> 1");// 設置返回狀態pIrp->IoStatus.Information = 1;stauts = STATUS_SUCCESS;break;}case OPER2:{DbgPrint("調用IRP_MJ_DEVICE_CONTROL —> 2 接收字節數:%d\n", uInLength);DbgPrint("調用IRP_MJ_DEVICE_CONTROL —> 2 輸出字節數:%d\n", uOutLength);// 讀緩存memcpy(&uRead,pIoBuffer,4);DbgPrint("調用IRP_MJ_DEVICE_CONTROL —> 2 地址:%llx",uRead);// 寫緩存memcpy(pIoBuffer,&uWrite,4);// 設置返回狀態pIrp->IoStatus.Information = 2;stauts = STATUS_SUCCESS;break;}}// 設置返回狀態pIrp->IoStatus.Status = stauts;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;}// 卸載函數
VOID DriverUnload(PDRIVER_OBJECT DriverObject) {DbgPrint("驅動被卸載了\n");
}NTSTATUS DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING reg_path) {NTSTATUS ntIoCreate = 0;PDEVICE_OBJECT pDeviceObject = NULL;UNICODE_STRING deviceName;UNICODE_STRING symbolicLinkName;// 創建設備名稱RtlInitUnicodeString(&deviceName, L"\\Device\\MyDevice");// 創建設備對象ntIoCreate = IoCreateDevice(driverObject, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);if (ntIoCreate != STATUS_SUCCESS) {DbgPrint("設備對象創建失敗!\n");return ntIoCreate;}// 設置數據的交互方式driverObject->Flags |= DO_BUFFERED_IO;// 創建符號鏈接名稱(給Ring3訪問)// Ring3用CreateFile打開設備時用 \\\\.\\MyTestDriverRtlInitUnicodeString(&symbolicLinkName, L"\\??\\MyTestDriver");// 創建符號鏈接ntIoCreate = IoCreateSymbolicLink(&symbolicLinkName, &deviceName);if(ntIoCreate != STATUS_SUCCESS) {DbgPrint("符號鏈接創建失敗!\n"); IoDeleteDevice(pDeviceObject);return ntIoCreate;}// 設置派遣函數和卸載函數driverObject->MajorFunction[IRP_MJ_CREATE] = IrpCreateProc;driverObject->MajorFunction[IRP_MJ_CLOSE] = IrpCloseProc;driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDeviceControlProc;driverObject->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}
演示效果