在驱动程序中,一般有两种方法使用定时器,一种方法是使用I/O定时器例程,另一
种方法是使用DPC例程。
每隔1S系统会调用一次I/0定时器例程,可以在定时器例程里面设置一个计数,每次定时器例程运行都将该计数-1.到0就调用自己的处理函数。这样就实现了任意时间间隔的定时。
初始化I/O定时器
NTSTATUS IoInitializeTimer(
PDEVICE_OBJECT DeviceObject, //I/O定时器关联的设备对象指针
PIO_TIMER_ROUTINE TimerRoutine, ///I/O定时器关联的定时器例程
__drv_aliasesMem PVOID Context //传入定时器例程的参数
);
开启I/O定时器
IoStartTimer
停止I/O定时器
IoStopTimer
示例代码
#include<ntddk.h>
#include<ntstatus.h>
#include "Driver.h"
#define DEVICE_NAME L"\\Device\\MyDevice"
#define SYMBOLICLINE_NAME L"\\??\\MyTestDriver" //ring3用CreateFile打开设备时,用"\\\\.\\MyTestDriver"//相当于起的别名
#define TIMEOUT 3
#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)
PVOID pDeviceExtension = 0;
//实现卸载函数
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
PDEVICE_OBJECT pNextObj;
KdPrint(("Enter DriverUnload\n"));
pNextObj = pDriverObject->DeviceObject;
__asm{ int 3}
while (pNextObj != NULL)
{
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pNextObj->DeviceExtension;
//删除符号链接
UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
IoDeleteSymbolicLink(&pLinkName);
pNextObj = pNextObj->NextDevice;
IoDeleteDevice(pDevExt->pDevice);
DbgPrint("删除设备\n");
}
}
NTSTATUS IrpDefaultProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;//getlasterror()得到的就是这个值
pIrp->IoStatus.Information = 0;//返回给3环多少数据,没有填0
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
IO_TIMER_ROUTINE IoTimerRoutine;
void IoTimerRoutine(
PDEVICE_OBJECT pDeviceObject,
PVOID Context
)
{
PDEVICE_EXTENSION pDevExt = pDeviceObject->DeviceExtension;
//将计数器-1
InterlockedDecrement(&pDevExt->TimeOut);
//如果计数器减少到0 重新赋值TIME_OUT 整个过程是互锁运算
ULONG prevCount = InterlockedCompareExchange(&pDevExt->TimeOut, TIMEOUT, 0);
PEPROCESS pEprocess = IoGetCurrentProcess();
if (strcmp((PUCHAR)pEprocess + 0x174,"Idle"))
{
DbgPrint("当前进程是:%s\n", (PUCHAR)pEprocess + 0x174);
}
if (!prevCount)
{
//自己的定时任务
}
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{
NTSTATUS status = 0;
ULONG uIndex = 0;
PDEVICE_OBJECT pDeviceObj = NULL;
UNICODE_STRING DeviceName;
UNICODE_STRING SymbolicLinkName;
//Irp默认处理
pDriver->MajorFunction[IRP_MJ_CREATE] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_CLOSE] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_WRITE] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_READ] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_CLEANUP] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_SET_INFORMATION] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_SHUTDOWN] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IrpDefaultProc;
//设置派遣函数和卸载函数
pDriver->DriverUnload = DriverUnload;
//创建设备名称
RtlInitUnicodeString(&DeviceName, DEVICE_NAME);
//创建设备 让三环的API能够找到,才能实现通信
status = IoCreateDevice(pDriver,
sizeof(DEVICE_EXTENSION), //扩展设备大小
&DeviceName,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&pDeviceObj);
if (status != STATUS_SUCCESS)
{
DbgPrint("创建设备失败! status=%x\r\n", status);
return status;
}
//设置交互数据方式
pDeviceObj->Flags |= DO_BUFFERED_IO;
//创建符号链接名称,就是给该设备在三环起个能用的别名
RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINE_NAME);
//创建符号链接
status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
if (!NT_SUCCESS(status))
{
DbgPrint("创建符号链接失败!\r\n");
IoDeleteDevice(pDeviceObj);
return status;
}
//初始化定时器
PDEVICE_EXTENSION pDevExt = pDeviceObj->DeviceExtension;
pDevExt->pDevice = pDeviceObj;
pDevExt->ustrDeviceName = DeviceName;
pDevExt->ustrSymLinkName = SymbolicLinkName;
//设置计数为3
pDevExt->TimeOut = TIMEOUT;
IoInitializeTimer(pDeviceObj,IoTimerRoutine,NULL);
//开启定时器 关闭使用IoStopTimer
IoStartTimer(pDeviceObj);
return STATUS_SUCCESS;
}
DPC定时器
在驱动程序中第二种使用定时器的方法是使用DPC定时器,这种定时器更加灵活,
可以对任意间隔时间进行定时。DPC定时器内部使用定时器对象KTIMER,当对定时器设
定一个时间间隔后,每隔这段时间操作系统就会将一个DPC例程插入DPC队列。当操作
系统读取DPC队列时,对应的DPC例程会被执行。DPC定时器例程相当于定时器的回调
函数。
在使用DPC定时器前,需要初始化DPC对象和定时器对象
初始化DPC对象
初始化定时器对象使用KeInitializeTimer
void KeInitializeDpc(
__drv_aliasesMem PRKDPC Dpc, DPC对象指针
PKDEFERRED_ROUTINE DeferredRoutine, //与DPC关联的DPC例程
__drv_aliasesMem PVOID DeferredContext //传入DPC例程的参数
);
开启定时器
BOOLEAN KeSetTimer(
PKTIMER Timer, //定时器对象指针
LARGE_INTEGER DueTime, //设定事件间隔 单位是100ns
PKDPC Dpc //传入DPC例程的参数
);
返回值:设定定时器成功返回TRUE
取消定时器
BOOLEAN KeCancelTimer(
PKTIMER Timer, //定时器对象指针
DPC定时器使用代码:
typedef struct _DEVICE_EXTENSION {
PDEVICE_OBJECT pDevice;
UNICODE_STRING ustrDeviceName; //设备名称
UNICODE_STRING ustrSymLinkName; //符号链接名
KDPC dpc;
KTIMER timer;
LARGE_INTEGER dueTime;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
#include<ntddk.h>
#include<ntstatus.h>
#include "Driver.h"
#define DEVICE_NAME L"\\Device\\MyDevice"
#define SYMBOLICLINE_NAME L"\\??\\MyTestDriver" //ring3用CreateFile打开设备时,用"\\\\.\\MyTestDriver"//相当于起的别名
#define TIMEOUT 3
#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)
PVOID pDeviceExtension = 0;
//实现卸载函数
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
PDEVICE_OBJECT pNextObj;
KdPrint(("Enter DriverUnload\n"));
pNextObj = pDriverObject->DeviceObject;
while (pNextObj != NULL)
{
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pNextObj->DeviceExtension;
//删除符号链接
UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
IoDeleteSymbolicLink(&pLinkName);
pNextObj = pNextObj->NextDevice;
IoDeleteDevice(pDevExt->pDevice);
DbgPrint("删除设备\n");
}
}
NTSTATUS IrpDefaultProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;//getlasterror()得到的就是这个值
pIrp->IoStatus.Information = 0;//返回给3环多少数据,没有填0
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
IO_TIMER_ROUTINE IoTimerRoutine;
#pragma LOCKEDCODE
void DpcRoutine(
PKDPC pDpc,
PVOID Context,
PVOID Arg1,
PVOID Arg2
)
{
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)Context;
PEPROCESS pEprocess = IoGetCurrentProcess();
DbgPrint("当前进程是:%s\n", (PUCHAR)pEprocess + 0x174);
//调用1次KeSetTimer只会运行一次DPC Routine
KeSetTimer(&pDevExt->timer, pDevExt->dueTime, &pDevExt->dpc);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{
NTSTATUS status = 0;
ULONG uIndex = 0;
PDEVICE_OBJECT pDeviceObj = NULL;
UNICODE_STRING DeviceName;
UNICODE_STRING SymbolicLinkName;
//Irp默认处理
pDriver->MajorFunction[IRP_MJ_CREATE] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_CLOSE] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_WRITE] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_READ] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_CLEANUP] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_SET_INFORMATION] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_SHUTDOWN] = IrpDefaultProc;
pDriver->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IrpDefaultProc;
//设置派遣函数和卸载函数
pDriver->DriverUnload = DriverUnload;
//创建设备名称
RtlInitUnicodeString(&DeviceName, DEVICE_NAME);
//创建设备 让三环的API能够找到,才能实现通信
status = IoCreateDevice(pDriver,
sizeof(DEVICE_EXTENSION), //扩展设备大小
&DeviceName,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&pDeviceObj);
if (status != STATUS_SUCCESS)
{
DbgPrint("创建设备失败! status=%x\r\n", status);
return status;
}
//设置交互数据方式
pDeviceObj->Flags |= DO_BUFFERED_IO;
//创建符号链接名称,就是给该设备在三环起个能用的别名
RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINE_NAME);
//创建符号链接
status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
if (!NT_SUCCESS(status))
{
DbgPrint("创建符号链接失败!\r\n");
IoDeleteDevice(pDeviceObj);
return status;
}
PDEVICE_EXTENSION pDevExt = pDeviceObj->DeviceExtension;
pDevExt->pDevice = pDeviceObj;
pDevExt->ustrDeviceName = DeviceName;
pDevExt->ustrSymLinkName = SymbolicLinkName;
pDevExt->dueTime.QuadPart = -1 * 1000 * 1000;
//初始化定时器对象
KeInitializeTimer(&pDevExt->timer);
//初始化DPC对象
KeInitializeDpc(&pDevExt->dpc, DpcRoutine, pDevExt);
KeSetTimer(&pDevExt->timer, pDevExt->dueTime, &pDevExt->dpc);
return STATUS_SUCCESS;
}