驱动开发:内核枚举IoTimer定时器

今天继续分享内核枚举系列知识,这次我们来学习如何通过代码的方式枚举内核IoTimer定时器,内核定时器其实就是在内核中实现的时钟,该定时器的枚举非常简单,因为在IoInitializeTimer初始化部分就可以找到IopTimerQueueHead地址,该变量内存储的就是定时器的链表头部 。枚举IO定时器的案例并不多见,即便有也是无法使用过时的 , 此教程学到肯定就是赚到了 。

驱动开发:内核枚举IoTimer定时器

文章插图
枚举Io定时器过程是这样的:
  • 1.找到IoInitializeTimer函数 , 该函数可以通过MmGetSystemRoutineAddress得到 。
  • 2.找到地址以后,我们向下增加0xFF偏移量,并搜索特征定位到IopTimerQueueHead链表头 。
  • 3.将链表头转换为IO_TIMER结构体 , 并循环链表头输出 。
这里解释一下为什么要找IoInitializeTimer这个函数他是一个初始化函数,既然是初始化里面一定会涉及到链表的存储问题,找到他就能找到定时器链表基址,该函数的定义如下 。
NTSTATUSIoInitializeTimer(IN PDEVICE_OBJECTDeviceObject,// 设备对象指针IN PIO_TIMER_ROUTINETimerRoutine,// 定时器例程IN PVOIDContext// 传给定时器例程的函数);接着我们需要得到IO定时器的结构定义,在DEVICE_OBJECT设备对象指针中存在一个Timer属性 。
lyshark.com: kd> dt _DEVICE_OBJECTntdll!_DEVICE_OBJECT+0x000 Type: Int2B+0x002 Size: Uint2B+0x004 ReferenceCount: Int4B+0x008 DriverObject: Ptr64 _DRIVER_OBJECT+0x010 NextDevice: Ptr64 _DEVICE_OBJECT+0x018 AttachedDevice: Ptr64 _DEVICE_OBJECT+0x020 CurrentIrp: Ptr64 _IRP+0x028 Timer: Ptr64 _IO_TIMER+0x030 Flags: Uint4B+0x034 Characteristics: Uint4B+0x038 Vpb: Ptr64 _VPB+0x040 DeviceExtension: Ptr64 Void+0x048 DeviceType: Uint4B+0x04c StackSize: Char+0x050 Queue: <anonymous-tag>+0x098 AlignmentRequirement : Uint4B+0x0a0 DeviceQueue: _KDEVICE_QUEUE+0x0c8 Dpc: _KDPC+0x108 ActiveThreadCount : Uint4B+0x110 SecurityDescriptor : Ptr64 Void+0x118 DeviceLock: _KEVENT+0x130 SectorSize: Uint2B+0x132 Spare1: Uint2B+0x138 DeviceObjectExtension : Ptr64 _DEVOBJ_EXTENSION+0x140 Reserved: Ptr64 Void
驱动开发:内核枚举IoTimer定时器

文章插图
这里的这个+0x028 Timer定时器是一个结构体_IO_TIMER其就是IO定时器的所需结构体 。
lyshark.com: kd> dt _IO_TIMERntdll!_IO_TIMER+0x000 Type: Int2B+0x002 TimerFlag: Int2B+0x008 TimerList: _LIST_ENTRY+0x018 TimerRoutine: Ptr64void+0x020 Context: Ptr64 Void+0x028 DeviceObject: Ptr64 _DEVICE_OBJECT
驱动开发:内核枚举IoTimer定时器

文章插图
如上方的基础知识有了也就够了,接着就是实际开发部分,首先我们需要编写一个GetIoInitializeTimerAddress()函数,让该函数可以定位到IoInitializeTimer所在内核中的基地址上面 , 具体实现调用代码如下所示 。
#include <ntifs.h>// 得到IoInitializeTimer基址// By: LyShark 内核开发系列教程PVOID GetIoInitializeTimerAddress(){ PVOID VariableAddress = 0; UNICODE_STRING uioiTime = { 0 }; RtlInitUnicodeString(&uioiTime, L"IoInitializeTimer"); VariableAddress = (PVOID)MmGetSystemRoutineAddress(&uioiTime); if (VariableAddress != 0) {return VariableAddress; } return 0;}VOID UnDriver(PDRIVER_OBJECT driver){ DbgPrint(("Uninstall Driver Is OK \n"));}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){ DbgPrint(("hello lyshark.com \n")); // 得到基址 PUCHAR IoInitializeTimer = GetIoInitializeTimerAddress(); DbgPrint("IoInitializeTimer Address = %p \n", IoInitializeTimer); Driver->DriverUnload = UnDriver; return STATUS_SUCCESS;}运行这个驱动程序,然后对比下是否一致:
驱动开发:内核枚举IoTimer定时器

文章插图
接着我们在反汇编代码中寻找IoTimerQueueHead,此处在LyShark系统内这个偏移位置是nt!IoInitializeTimer+0x5d 具体输出位置如下 。
lyshark.com: kd> uf IoInitializeTimernt!IoInitializeTimer+0x5d:fffff805`74b85bed 488d5008leardx,[rax+8]fffff805`74b85bf1 48897018movqword ptr [rax+18h],rsifffff805`74b85bf5 4c8d054475e0fflear8,[nt!IopTimerLock (fffff805`7498d140)]fffff805`74b85bfc 48897820movqword ptr [rax+20h],rdifffff805`74b85c00 488d0dd9ddcdfflearcx,[nt!IopTimerQueueHead (fffff805`748639e0)]fffff805`74b85c07 e8141e98ffcallnt!ExInterlockedInsertTailList (fffff805`74507a20)fffff805`74b85c0c 33c0xoreax,eax【驱动开发:内核枚举IoTimer定时器】在WinDBG中标注出颜色

推荐阅读