驅動開發:內核枚舉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中標注出顏色

推薦閱讀