高手进阶windows内核定时器之一


谈到定时器在ring3下有一个,启动和关闭都比较简单,通过两个api函数SetTimer和KillTimer来完成的。对于ring0中的定时器,稍微复杂一些。
Ring0 下的定时器有两个,今天我们先看一个。
即:利用I/O定时器例程实现的。用于进行固定的1秒时间间隔的操作定时。对应的函数有三个。


  

在IoInitializeTimer 函数中,我们设置回调函数,回调函数定义格式如下:
VOID  (*PIO_TIMER_ROUTINE) ( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PVOID Context 
    ); 
说明如下:
 

  

对于这三个函数,我们用windbg看看都作了些什么工作。
一、NTSTATUS  IoInitializeTimer( 
    IN PDEVICE_OBJECT  DeviceObject, 
    IN PIO_TIMER_ROUTINE  TimerRoutine, 
    IN PVOID  Context 
    ); 

typedef struct _IO_TIMER
{
     SHORT Type;
     SHORT TimerFlag;
     LIST_ENTRY TimerList;
     PVOID TimerRoutine;
     PVOID Context;
     PDEVICE_OBJECT DeviceObject;
} IO_TIMER, *PIO_TIMER;

lkd> u IoInitializeTimer l 50
nt!IoInitializeTimer:
80569792 8bff            mov     edi,edi
80569794 55              push    ebp
80569795 8bec            mov     ebp,esp
80569797 56              push    esi
80569798 8b7508          mov     esi,dword ptr [ebp+8]  ;参数1,DeviceObject
8056979b 8b5618          mov     edx,dword ptr [esi+18h];DeviceObject->Timer
8056979e 85d2            test    edx,edx  
;判断DEVICE_OBJECT中的Timer是否为null. 如果为空则为其申请内存,然后再初始化
805697a0 7530            jne     nt!IoInitializeTimer+0x40 (805697d2)
805697a2 68496f5469      push    69546F49h  ;"IoTI"
805697a7 6a18            push    18h
805697a9 52              push    edx
805697aa e8d1bcfdff      call    nt!ExAllocatePoolWithTag (80545480)
805697af 8bd0            mov     edx,eax
805697b1 85d2            test    edx,edx
805697b3 7507            jne     nt!IoInitializeTimer+0x2a (805697bc)
;如果申请内存不成功则,直接返回STATUS_INSUFFICIENT_RESOURCES
805697b5 b89a0000c0      mov     eax,0C000009Ah
805697ba eb36            jmp     nt!IoInitializeTimer+0x60 (805697f2)

;内存申请成功,则初始化申请的24字节内存为0,IO_TIMER大小为24字节
805697bc 57              push    edi
805697bd 6a06            push    6
805697bf 59              pop     ecx
805697c0 33c0            xor     eax,eax
805697c2 8bfa            mov     edi,edx
805697c4 f3ab            rep stos dword ptr es:[edi]

805697c6 66c7020900      mov     word ptr [edx],9 ;设置IO_TIMER.Type
;将参数1,DeviceObject赋值给IO_TIMER.DeviceObject
805697cb 897214          mov     dword ptr [edx+14h],esi
;DeviceObject->Timer 指向刚申请的IO_TIMER内存
805697ce 895618          mov     dword ptr [esi+18h],edx 
805697d1 5f              pop     edi

;开始初始化DeviceObject->Timer
805697d2 8b450c          mov     eax,dword ptr [ebp+0Ch] ;取TimerRoutine参数
;设置IO_TIMER.TimerRoutine = 参数2,TimerRoutine
805697d5 89420c          mov     dword ptr [edx+0Ch],eax

;取参数3 Context
805697d8 8b4510          mov     eax,dword ptr [ebp+10h]
;设置IO_TIMER.Context = 参数3 Context
805697db 894210          mov     dword ptr [edx+10h],eax

805697de 6844b35480      push    offset nt!IopTimerLock (8054b344) ;参数3
805697e3 83c204          add     edx,4                             ;参数2
805697e6 b9601e5580      mov     ecx,offset nt!IopTimerQueueHead (80551e60) ;参数1
805697eb e8f893fdff      call    nt!ExfInterlockedInsertTailList (80542be8);调用
805697f0 33c0            xor     eax,eax
805697f2 5e              pop     esi
805697f3 5d              pop     ebp
805697f4 c20c00          ret     0Ch

下面看看ExfInterlockedInsertTailList函数:
 PLIST_ENTRY _fastcall 
 ExfInterlockedInsertTailList(PLIST_ENTRY ListHead , PLIST_ENTRY 
 ListEntry , PKSPIN_LOCK Lock ) ;
 
由于采用fastcall调用约定, ecx = ListHead ,edx = ListEntry ,[ebp+8] = 参数3

该函数功能是把IO_TIMER.TimerList加入对象链表。
nt!ExfInterlockedInsertTailList:   
80542be8 9c              pushfd 
80542be9 fa              cli
;eax = ListHead.Blink 
80542bea 8b4104          mov     eax,dword ptr [ecx+4]     
; ListEntry.Flink = ListHead 
80542bed 890a            mov     dword ptr [edx],ecx    
; ListEntry.Blink = ListHead.Blink   
80542bef 894204          mov     dword ptr [edx+4],eax     
;ListHead.Blink = ListEntry
80542bf2 895104          mov     dword ptr [ecx+4],edx     
;ListHead.Blink Flink  = ListEntry
80542bf5 8910            mov     dword ptr [eax],edx       
80542bf7 9d              popfd
80542bf8 33c1            xor     eax,ecx
80542bfa 7402            je      nt!ExfInterlockedInsertTailList+0x16 (80542bfe)
80542bfc 33c1            xor     eax,ecx
80542bfe c20400          ret     4

其中,ListHead 对应于
805697e6 b9601e5580      mov     ecx,offset nt!IopTimerQueueHead (80551e60) ;参数1
这个ListHead是: 
lkd> dd 80551e60
80551e60  89aaf434 8987852c
其中:ListHead.Flink = 89aaf434, ListHead.Blink = 8987852c

二、VOID  IoStartTimer(
    IN PDEVICE_OBJECT  DeviceObject
    );

lkd> u IoStartTimer l 30
nt!IoStartTimer:
804f02da 8bff            mov     edi,edi
804f02dc 55              push    ebp
804f02dd 8bec            mov     ebp,esp
804f02df 8b4d08          mov     ecx,dword ptr [ebp+8] ;取参数
804f02e2 8b4118          mov     eax,dword ptr [ecx+18h];取DeviceObject->Timer

;取DeviceObject->DeviceObjectExtension
804f02e5 8b89b0000000    mov     ecx,dword ptr [ecx+0B0h]

;DeviceObject->DeviceObjectExtension.ExtensionFlags = 0Fh 
804f02eb f641100f        test    byte ptr [ecx+10h],0Fh 

804f02ef 7515            jne     nt!IoStartTimer+0x2c (804f0306)
804f02f1 fa              cli

;DeviceObject->Timer.TimerFlag与0比较
804f02f2 6683780200      cmp     word ptr [eax+2],0 
804f02f7 750c            jne     nt!IoStartTimer+0x2b (804f0305) ; != 0跳

;DeviceObject->Timer.TimerFlag = 1
804f02f9 66c740020100    mov     word ptr [eax+2],1 

;计数变量+1
804f02ff ff05f41d5580    inc     dword ptr [nt!IoAdapterObjectType+0x4 (80551df4)]

804f0305 fb              sti
804f0306 5d              pop     ebp
804f0307 c20400          ret     4

三,VOID  IoStopTimer(
    IN PDEVICE_OBJECT  DeviceObject
    );

lkd> u IoStopTimer l 20
nt!IoStopTimer:
804f0310 8bff            mov     edi,edi
804f0312 55              push    ebp
804f0313 8bec            mov     ebp,esp
804f0315 8b4508          mov     eax,dword ptr [ebp+8] ;取参数
804f0318 8b4018          mov     eax,dword ptr [eax+18h];取DeviceObject->Timer
804f031b fa              cli

;DeviceObject->Timer.TimerFlag与0比较
804f031c 6683780200      cmp     word ptr [eax+2],0
804f0321 740b            je      nt!IoStopTimer+0x1e (804f032e) ;=0跳

;DeviceObject->Timer.TimerFlag = 0
804f0323 6683600200      and     word ptr [eax+2],0

;计数变量-1
804f0328 ff0df41d5580    dec     dword ptr [nt!IopTimerCount (80551df4)]
804f032e fb              sti
804f032f 5d              pop     ebp
804f0330 c20400          ret     4

总结:通过上述分析可以看出这个定时器跟一个驱动程序创建的设备对象相关联,一个设备只能对应一个这样的定时器。定时器的启停在于DeviceObject->Timer.TimerFlag值。并且这个Timer位于DeviceObject->Timer。

你可能感兴趣的:(c,windows,timer,IO,object,resources)