首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
80 阅读
2
nvim番外之将配置的插件管理器更新为lazy
58 阅读
3
2018总结与2019规划
54 阅读
4
PDF标准详解(五)——图形状态
33 阅读
5
为 MariaDB 配置远程访问权限
30 阅读
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
登录
Search
标签搜索
c++
c
学习笔记
windows
文本操作术
编辑器
NeoVim
Vim
win32
VimScript
Java
emacs
linux
文本编辑器
elisp
反汇编
OLEDB
数据库编程
数据结构
内核编程
Masimaro
累计撰写
308
篇文章
累计收到
27
条评论
首页
栏目
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
页面
归档
友情链接
关于
搜索到
1
篇与
的结果
2017-02-16
定时器的实现
使用IO定时器IO定时器每隔1s就会触发一次,从而进入到定时器例程中,如果某个操作是每n秒执行一次(n为正整数)可以考虑在定时器例程中记录一个计数器大小就为n,每次进入定时器例程中时将计数器减一,当计数器为0时,表示到达n秒,这个时候可以执行操作。IO定时器只适合处理整数秒的情况在使用IO定时器之前需要对定时器进行初始化,初始化函数为IoInitializeTimer,定义如下:NTSTATUS IoInitializeTimer( IN PDEVICE_OBJECT DeviceObject, //设备对象指针 IN PIO_TIMER_ROUTINE TimerRoutine,//定时器例程 IN PVOID Context//传给定时器例程的函数 );初始化完成后可以使用IoStartTimer来启动定时器,使用IoStopTimer来停止定时器,下面是一个例子#define PAGEDCODE code_seg("PAGE") #define LOCKEDCODE code_seg() #define INITCODE code_seg("INIT") #define PAGEDDATA data_seg("PAGE") #define LOCKEDDATA data_seg() #define INITDATA data_seg("INIT") typedef struct _tag_DEVICE_EXTENSION { PDEVICE_OBJECT DeviceObject; UNICODE_STRING uDeviceName; UNICODE_STRING uSymbolickName; LONG lTimerCount; //定时器触发时间,以秒为单位 }DEVICE_EXTENSION, *PDEVICE_EXTENSION; NTSTATUS DriverEntry(DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath) { NTSTATUS status; LONG i; PDEVICE_OBJECT pDeviceObject; UNREFERENCED_PARAMETER(RegistryPath); DriverObject->DriverUnload = DriverUnload; //设置派遣函数,这些代码在这就省略了 status = CreateDevice(DriverEntry, &pDeviceObject); IoStartTimer(pDeviceObject); return status; } #pragma LOCKEDCODE VOID IoTimer(DEVICE_OBJECT *DeviceObject,PVOID Context) { LONG ret; PDEVICE_EXTENSION pDeviceExtension; UNICODE_STRING uProcessName; PEPROCESS pCurrProcess; UNREFERENCED_PARAMETER(Context); pDeviceExtension = (PDEVICE_EXTENSION)(DeviceObject->DeviceExtension); ASSERT(NULL != pDeviceExtension); //采用互锁操作将定时器数减一 InterlockedDecrement(&pDeviceExtension->lTimerCount); //判断当前时间是否到达3秒 ret = InterlockedCompareExchange(&pDeviceExtension->lTimerCount, TIME_OUT, 0); if(0 == ret) { DbgPrint("3s time out\n"); } pCurrProcess = IoGetCurrentProcess(); RtlInitUnicodeString(&uProcessName, (PTSTR)((ULONG)pCurrProcess + 0x174)); DbgPrint("the current process %wZ", uProcessName); } #pragma INITCODE NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject,PDEVICE_OBJECT *ppDeviceObject) { NTSTATUS status; UNICODE_STRING uDeviceName; UNICODE_STRING uSymbolickName; PDEVICE_EXTENSION pDeviceExtension; RtlInitUnicodeString(&uDeviceName, DEVICE_NAME); RtlInitUnicodeString(&uSymbolickName, SYMBOLICK_NAME); if(NULL != ppDeviceObject) { //创建设备对象并填充设备扩展中的变量 ... IoInitializeTimer(*ppDeviceObject, IoTimer, NULL); status = IoCreateSymbolicLink(&uSymbolickName, &uDeviceName); if(!NT_SUCCESS(status)) { //出错的话就做一些清理工作 ... return status; } if(NULL != pDeviceExtension) { RtlInitUnicodeString(&pDeviceExtension->uSymbolickName, SYMBOLICK_NAME); } return status; } return STATUS_UNSUCCESSFUL; }需要注意的是IO定时器例程是位于DISPATCH_LEVEL,所以它不能使用分页内存,所以在函数前加上一句#pragma LOCKEDCODE,表示它在非分页内存中DPC定时器DPC定时器相比IO定时器来说更加灵活,它可以指定任何时间间隔。DPC内部使用KTIMER这个内核对象进行定时,每当时间到达设置的时间,那么系统就会将对应的DPC例程加入到DPC队列中,当系统读取DPC队列时,这个DPC例程就会被执行,使用DPC定时器的步骤一般是:分别调用KeInitializeTimer和KeInitializeDpc初始化KTIMER对象和DPC对象用KeSetTimer开启定时器在DPC例程中再次调用KeSetTimer开启定时器调用KeCancelTimer关闭定时器由于每次执行KeSetTimer都只会触发一次DPC例程,所以如果想要周期性的调用DPC例程,需要在DPC例程中再次调用KeSetTimer。这些函数的定义如下:VOID KeInitializeDpc( IN PRKDPC Dpc, //DPC对象 IN PKDEFERRED_ROUTINE DeferredRoutine, //DPC例程 IN PVOID DeferredContext//传给DPC例程的参数 ); BOOLEAN KeSetTimer( IN PKTIMER Timer,//定时器 IN LARGE_INTEGER DueTime, //隔多久触发这个DPC例程,这个值是正数则表示从1601年1月1日到触发这个DPC例程所经历的时间,为负数,则表示从当前时间,间隔多长时间后触发,单位为100ns IN PKDPC Dpc OPTIONAL //传入上面初始化的DPC对象 );下面是一个使用的例子typedef struct _tag_DEVICE_EXTENSION { PDEVICE_OBJECT pDeviceObj; UNICODE_STRING uDeviceName; UNICODE_STRING uSymbolickName; KTIMER timer; KDPC Dpc; }DEVICE_EXTENSION, *PDEVICE_EXTENSION; NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) { PDEVICE_EXTENSION pDeviceExtension; PDEVICE_OBJECT pDeviceObj; int i; NTSTATUS status; LARGE_INTEGER time_out; UNREFERENCED_PARAMETER(pRegistryPath); pDriverObject->DriverUnload = DriverUnload; //设置派遣函数 ... status = CreateDevice(pDriverObject, &pDeviceObj); //失败处理 ... //设置定时器 time_out.QuadPart = -1 * 10000000; //1s = 1000000000ns status = KeSetTimer(&pDeviceExtension->timer,time_out, &pDeviceExtension->Dpc); return STATUS_SUCCESS; } VOID DriverUnload(PDRIVER_OBJECT pDriverObject) { //该函数主要用来清理相关资源 ... } NTSTATUS DefauleDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { //默认返回成功 } NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObj, PDEVICE_OBJECT *ppDeviceObj) { PDEVICE_EXTENSION pDevEx; PDEVICE_OBJECT pDevObj; UNICODE_STRING uDeviceName; UNICODE_STRING uSymbolicName; NTSTATUS status; //创建设备对象,填充扩展设备内容 ... //初始化KTIMER DPC KeInitializeTimer(&pDevEx->timer); KeInitializeDpc(&pDevEx->Dpc, TimerDpc, pDevObj); //设置连接符号 ... return STATUS_SUCCESS; } VOID TimerDpc( __in struct _KDPC *Dpc, __in_opt PVOID DeferredContext, __in_opt PVOID SystemArgument1, __in_opt PVOID SystemArgument2 ) { static int i = 0; PTSTR pProcessName; PEPROCESS pEprocess; LARGE_INTEGER time_out; PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)DeferredContext; PDEVICE_EXTENSION pDevEx = (PDEVICE_EXTENSION)(pDevObj->DeviceExtension); ASSERT(NULL != pDevObj); pEprocess = PsGetCurrentProcess(); pProcessName = (PTSTR)((ULONG)pEprocess + 0x174); DbgPrint("%d Call TimerDpc, Process: %s\n", i, pProcessName); time_out.QuadPart = -1 * 10000000; //1s = 1000000000ns KeSetTimer(&pDevEx->timer, time_out, &pDevEx->Dpc); i++; }
2017年02月16日
7 阅读
0 评论
0 点赞