DCP是一種使用更加靈活的定時器,可以對任意間隔時間進行定時。DPC定時器的內部使用了一個定時器對象KTIMER,當你設定了定時器之后,從設定開始起經過這個時間之后操作系統會將一個DPC定時器的例程插入到DPC的隊列,操作系統讀取DPC隊列的時候定時器例程就能夠被執行。這里的DPC定時器例程就相當於一個定時器的回調函數。
在使用需要一些相關的初始化操作
1,初始化Timer
VOID KeInitializeTimer(PKTIMER Timer); //參數Timer是定時器的指針
2,初始化DPC對象
VOID KeInitializeDpc(PRKDPC Dpc,PKDEFERRED_ROUTINE DeferredRoutine,PVOID DeferredContext); //Dpc是輸入參數DPC的對象指針 //DeferredRoutine是一個與DPC關聯的定時器例程函數,當定時器被觸發的時候這個例程函數就會被執行調用 //DeferredContext是一個傳入定時器例程的參數
3,當初始化完成之后使用函數KeSetTimer函數開啟定時器,
BOOLEAN KeSetTimer( PKTIMER Timer,LARGE_INTEGER DueTime,PKDPC Dpc); //Timer是定時器對象的指針. //DueTimer這個參數是設定的時間間隔. //Dpc表示傳入定時器例程的參數. //返回值:BOOL類型的,表示成功或者失敗.
4,取消定時器使用內核函數KeCancelTimer,
BOOLEAN KeCancelTimer(PKTIMER Timer);
在調用KeSetTimer函數之后,經過DueTime的時間,操作系統會調用一次定時器的例程,其中如果DueTime是一個正整數,則會代表絕對時間,也就是相對於1601年1月1日到觸發DPC定時器的那個時刻,如果DueTime是負數,那它表示的是間隔多長時間,DueTime的單位是100ns。
示例代碼:
用戶層
#define IO_CONTROL_TRANSMIT_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN,0x8080,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IO_CONTROL_START_TIMER CTL_CODE(FILE_DEVICE_UNKNOWN,0x8081,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IO_CONTROL_STOP_TIMER CTL_CODE(FILE_DEVICE_UNKNOWN,0x8082,METHOD_IN_DIRECT,FILE_ANY_ACCESS) int main() { HANDLE hDevice = CreateFile(L"\\\\.\\MyDeviceSymbolLinkName01", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hDevice == INVALID_HANDLE_VALUE) { printf("failed to obtain file handle to device with win32 error code %d ...\n", GetLastError()); return 1; } DWORD dwOutput; DWORD dwMircoSeconds = 1000 * 1000 * 2;//100ns一個單位 //發送啟動定時器命令 DeviceIoControl(hDevice, IO_CONTROL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL); Sleep(20000); //發送終止定時器命令 DeviceIoControl(hDevice, IO_CONTROL_STOP_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL); CloseHandle(hDevice); return 0; }
驅動層:
//FirstDriver.h #pragma once #define IO_CONTROL_TRANSMIT_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN,0x8080,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IO_CONTROL_START_TIMER CTL_CODE(FILE_DEVICE_UNKNOWN,0x8081,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IO_CONTROL_STOP_TIMER CTL_CODE(FILE_DEVICE_UNKNOWN,0x8082,METHOD_IN_DIRECT,FILE_ANY_ACCESS) typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT pDevObj; UNICODE_STRING ustrDeviceName; UNICODE_STRING ustrSymbolLinkName; KDPC pollingDPC; KTIMER pollingTimer; LARGE_INTEGER pollingInterVal; }DEVICE_EXTENSION, * PDEVICE_EXTENSION; NTSTATUS unload(PDRIVER_OBJECT driver); NTSTATUS DemoDeviceControlDispatch(PDEVICE_OBJECT pDeviceObject, PIRP pIrp); NTSTATUS DeviceCreate(PDEVICE_OBJECT pDeviceObject, PIRP pIrp); NTSTATUS DeviceClose(PDEVICE_OBJECT pDeviceObject, PIRP pIrp); NTSTATUS DemoCreateDevice(PDRIVER_OBJECT pDriver, PCWSTR devName, PCWSTR devSymName);
//FirstDriver.c #include <ntddk.h> #include "FirstDriver.h" NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) { NTSTATUS ntstatus = STATUS_SUCCESS; driver->DriverUnload = unload; driver->MajorFunction[IRP_MJ_CREATE] = DeviceCreate;//創建 driver->MajorFunction[IRP_MJ_CLOSE] = DeviceClose;//關閉 driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DemoDeviceControlDispatch; ntstatus = DemoCreateDevice(driver, L"\\Device\\MyDevice01", L"\\??\\MyDeviceSymbolLinkName01"); if (!NT_SUCCESS(ntstatus)) { DbgPrint("IoCreateDevice Failed"); return ntstatus; } DbgPrint("%ws", reg_path->Buffer); DbgPrint("driver load success..."); return STATUS_SUCCESS; } VOID PollingTimerDPC(PKDPC pDpc, PVOID pContext, PVOID SysArg1, PVOID SysArg2) { PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext; PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; KeSetTimer(&pdx->pollingTimer, pdx->pollingInterVal, &pdx->pollingDPC); KdPrint(("PollingTimerDpc\n")); //檢驗是運行在任意線程上下文 PEPROCESS pEProcess = IoGetCurrentProcess(); PTSTR ProcessName = (PTSTR)((LONGLONG)pEProcess + 0x174); DbgPrint("多余參數 %d , %d , %d", pDpc->Number, SysArg1, SysArg2); DbgPrint("%s\n", ProcessName); } NTSTATUS DemoDeviceControlDispatch(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { NTSTATUS ntstatus = STATUS_SUCCESS; DbgPrint("enter DemoDeviceControlDispatch ...\n"); PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); //ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength; //ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength; ULONG ctlCode = stack->Parameters.DeviceIoControl.IoControlCode; PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension; ULONG info = 0; switch (ctlCode) { case IO_CONTROL_START_TIMER: { KdPrint(("IOCTL_START_TIMER!\n")); //從用戶模式傳進來的超時 ULONG ulMircoSeconds = *(PULONG)pIrp->AssociatedIrp.SystemBuffer; pDevExt->pollingInterVal = RtlConvertLongToLargeInteger(ulMircoSeconds * -10); KeSetTimer(&pDevExt->pollingTimer, pDevExt->pollingInterVal, &pDevExt->pollingDPC); break; } case IO_CONTROL_STOP_TIMER: { KdPrint(("IOCTL_STOP_TIMER!\n")); KeCancelTimer(&pDevExt->pollingTimer); break; } default: ntstatus = STATUS_INVALID_VARIANT; break; } pIrp->IoStatus.Status = ntstatus; pIrp->IoStatus.Information = info; IoCompleteRequest(pIrp, IO_NO_INCREMENT); DbgPrint("leave the demo device control dispatch ..."); DbgPrint("device io control test success...%d", pDeviceObject->ActiveThreadCount); return ntstatus; } NTSTATUS DeviceCreate(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { //業務代碼區 //設置返回狀態 pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); DbgPrint("create device success...%d", pDeviceObject->ActiveThreadCount); return STATUS_SUCCESS; } NTSTATUS DeviceClose(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { //業務代碼區 //設置返回狀態 pIrp->IoStatus.Status = STATUS_SUCCESS;//getLastError()得到的值 pIrp->IoStatus.Information = 0; //返回給3環多少數據,沒有填0 IoCompleteRequest(pIrp, IO_NO_INCREMENT); DbgPrint("close device success...%d", pDeviceObject->ActiveThreadCount); return STATUS_SUCCESS; } NTSTATUS DemoCreateDevice(PDRIVER_OBJECT pDriver, PCWSTR devName, PCWSTR devSymName) { PDEVICE_OBJECT pDevice; PDEVICE_EXTENSION pDevExt; UNICODE_STRING DeviceName; UNICODE_STRING SymbolLinkName; RtlInitUnicodeString(&DeviceName, devName); RtlInitUnicodeString(&SymbolLinkName, devSymName); NTSTATUS ntstatus = STATUS_SUCCESS; ntstatus = IoCreateDevice(pDriver, sizeof(DEVICE_EXTENSION), &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevice); if (!NT_SUCCESS(ntstatus)) { DbgPrint("IoCreateDevice Failed"); return ntstatus; } ntstatus = IoCreateSymbolicLink(&SymbolLinkName, &DeviceName); if (!NT_SUCCESS(ntstatus)) { DbgPrint("IoCreateSymbolicLink Failed"); IoDeleteDevice(pDevice); return ntstatus; } pDevice->Flags |= DO_BUFFERED_IO; pDevExt = (PDEVICE_EXTENSION)pDevice->DeviceExtension; pDevExt->pDevObj = pDevice; pDevExt->ustrDeviceName = DeviceName; pDevExt->ustrSymbolLinkName = SymbolLinkName; KeInitializeTimer(&pDevExt->pollingTimer); KeInitializeDpc(&pDevExt->pollingDPC, PollingTimerDPC, (PVOID)pDevice); return ntstatus; } NTSTATUS unload(PDRIVER_OBJECT driver) { PDEVICE_OBJECT pDev; DbgPrint("driver :%ws unload", driver->DriverName.Buffer); pDev = driver->DeviceObject; while (pDev != NULL) { PDEVICE_EXTENSION pDevExt = { 0 }; pDevExt = (PDEVICE_EXTENSION)pDev->DeviceExtension; //刪除符號鏈接 UNICODE_STRING pLinkName = pDevExt->ustrSymbolLinkName; DbgPrint("this is the divice name : %ws", pLinkName.Buffer); IoDeleteSymbolicLink(&pLinkName); pDev = pDev->NextDevice; IoDeleteDevice(pDevExt->pDevObj); } DbgPrint("driver unload success..."); return STATUS_SUCCESS; }