首页
论坛
课程
招聘
雪    币: 108
活跃值: 活跃值 (34)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝

[原创]高手进阶windows内核定时器之一

2008-3-1 00:14 21586

[原创]高手进阶windows内核定时器之一

2008-3-1 00:14
21586
谈到定时器在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。
代码附上:

[公告]看雪论坛2020激励机制上线了!多多参与讨论可以获得积分快速升级?

上传的附件:
最新回复 (17)
雪    币: 461
活跃值: 活跃值 (64)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2008-3-1 10:23
2
0
1 .KeInitializeTimer --> KeInitializeDpc --> KeSetTimerEx --> MyDpcRoutine -->干邪恶的事情~~

KeDelayExecutionThread。



2. ZwCreateEvent --> PsCreateSystemThread --> ZwNotifyXXXX--> ZwWaitForSingleObject --> MyEventRoutine 中干邪恶的事...

哈哈.都和内核对象同步,Timer等有关.病毒经常这样做~~
雪    币: 220
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhtjia 活跃值 2008-3-1 13:02
3
0
好文,学习...
雪    币: 235
活跃值: 活跃值 (10)
能力值: ( LV12,RANK:460 )
在线值:
发帖
回帖
粉丝
火影 活跃值 11 2008-3-1 22:11
4
0
学习 .......
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
zhoujiamur 活跃值 1 2008-6-24 15:50
5
0
学习中发现一个问题:
DelayedWorkQueue
附件里面这个找不到定义 用Kmdkit + Masm9.0 编译不过,请教楼主
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
zhoujiamur 活跃值 1 2008-6-24 16:20
6
0
不好意思,原来是DDK的常数
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
zhoujiamur 活跃值 1 2008-6-24 16:32
7
0
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
  NTSTATUS v2;
  NTSTATUS v3;
  NTSTATUS status;
  PDEVICE_OBJECT DeviceObject;

  status = STATUS_DEVICE_CONFIGURATION_ERROR
  g_fTimerStarted = FALSE;
  g_nWorkToDo = 0;
  if ( !IoCreateDevice(DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, 0, 1u, &DeviceObject) )
  {
    v2 = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
    if ( v2 )
    {
      DbgPrint("WorkItem: Couldn't create device. Status: %08X\r\n", v2);
      IoDeleteDevice(DeviceObject);
    }
    else
    {
      DriverObject->DriverUnload = (PDRIVER_UNLOAD)DriverUnload;
      v3 = IoInitializeTimer(DeviceObject, TimerRoutine, 0);
      if ( v3  != STATUS_SUCCESS)
      {
        DbgPrint("WorkItem: Couldn't initialize timer. Status: %08X\r\n", v3);
        IoDeleteSymbolicLink(&SymbolicLinkName);
        IoDeleteDevice(DeviceObject);
      }
      else
      {
        g_nWorkToDo = 5;                                        // Number of jobs to do
        IoStartTimer(DeviceObject);
        g_fTimerStarted = 1;
        DbgPrint("WorkItem: Timer started\r\n");
        status = 0;
      }
    }
  }
  return status;
}
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
zhoujiamur 活跃值 1 2008-6-24 16:34
8
0
NTSTATUS DriverUnload(PDRIVER_OBJECT DriverObject)
{
  IoDeleteSymbolicLink(&SymbolicLinkName);
  if ( g_fTimerStarted )
  {
    IoStopTimer(DriverObject->DeviceObject);
    g_fTimerStarted = FALSE;
    DbgPrint("WorkItem: Timer stopped\r\n");
  }
  IoDeleteDevice(DriverObject->DeviceObject);
}
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
zhoujiamur 活跃值 1 2008-6-24 16:46
9
0
type struct _WORK{
PIO_WORKITEM pIoWorkItem;
LONG  nWorkNumber;
}WORK,*PWORK;

void  WorkItemRoutine(PDEVICE_OBJECT pDeviceObject, PVOID pContext)
{
  PWORK pWork;

  pWork = (PWORK)pContext;
  DbgPrint("WorkItem: Work #%d is done\r\n", pWork->nWorkNumber);
  IoFreeWorkItem(pWork->pIoWorkItem);
  ExFreePool(pWork);
}
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
zhoujiamur 活跃值 1 2008-6-24 16:52
10
0
void TimerRoutine(struct _DEVICE_OBJECT *pDeviceObject, PVOID pContext)
{
  PWORK pWork;
  PIO_WORKITEM IoWorkItem;

  if ( g_nWorkToDo )
  {
    IoWorkItem = IoAllocateWorkItem(pDeviceObject);
    if ( IoWorkItem )
    {
      pWork = ExAllocatePool(0, sizeof(WORK));
      if ( pWork != NULL )
      {
        pWork->pIoWorkItem = IoWorkItem;
        pWork->nWorkNumber = g_nWorkToDo;
        IoQueueWorkItem(IoWorkItem, WorkItemRoutine, DelayedWorkQueue, pWork);
        --g_nWorkToDo;
      }
    }
  }
  else
  {
    IoStopTimer(pDeviceObject);
    g_fTimerStarted = FALSE;
  }
}
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
zhoujiamur 活跃值 1 2008-6-24 16:55
11
0
俄国人的汇编驱动确实牛气,不过看不习惯,我把它用C改写了
雪    币: 892
活跃值: 活跃值 (23)
能力值: ( LV9,RANK:570 )
在线值:
发帖
回帖
粉丝
mickeylan 活跃值 14 2008-6-24 17:21
12
0
来晚了,连坐在地上的位置都没了
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
zhoujiamur 活跃值 1 2008-6-24 17:56
13
0
附上编译的几个文件
上传的附件:
雪    币: 212
活跃值: 活跃值 (10)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
安摧 活跃值 2 2009-1-7 18:24
14
0
NTSTATUS
  IoInitializeTimer(
    IN PDEVICE_OBJECT  pDevObj,
    IN PIO_TIMER_ROUTINE  TimerRoutine,
    IN PVOID  Context
    )
{
        if(!(pDevObj->Timer))
        {
                PIO_TIMER pTimer = (PIO_TIMER)ExAllocatePoolWithTag(NonPagedPool, sizeof(IO_TIMER), 0X69546F49);
                if(!pTimer)
                {
                        return STATUS_INSUFFICIENT_RESOURCES;
                }

                memset(pTimer, sizeof(IO_TIMER), 0);
                pTimer->Type = 9;
                pTimer->DeviceObject = pDevObj;
                pDevObj->Timer = pTimer;
        }

        pTimer->TimerRoutine = TimerRoutine;
        pTimer->Context = Context;

        ExfInterlockedInsertTailList(IopTimerQueueHead, pTimer->TimerList, IopTimerLock);
        return STATUS_SUCCESS;
}

PLIST_ENTRY __fastcall ExfInterlockedInsertTailList(PLIST_ENTRY Header, PLIST_ENTRY newItem, SOME_LOCK lock)
{
        //PLIST_ENTRY newHeader;

        __asm
        {
                pushfd
                cli
        }

        newItem->Flink = Header;
        newItem->Blink = Header->Blink;
        Header->Blink->Flink = newItem;
        Header->Blink = newItem;

        __asm
        {
                popfd
        }

        if(Header->Blink = Header)
        {
                return NULL;
        }

        return Header;
}

VOID
  IoStartTimer(
    IN PDEVICE_OBJECT  DeviceObject)
{
        if(pDevObj->DeviceObjectExtension->ExtensionFlags & 0x0f)
        {
                __asm
                {
                        cli
                }

                if(!(pDevObj->Timer->TimerFlag))
                {
                        pDevObj->Timer->TimerFlag = 1;
                        IopTimerCount++;
                }

                __asm
                {
                        sti
                }
        }
}

VOID
  IoStartTimer(
    IN PDEVICE_OBJECT  DeviceObject)
{
        if(pDevObj->DeviceObjectExtension->ExtensionFlags & 0x0f)
        {
                __asm
                {
                        cli
                }

                if(!(pDevObj->Timer->TimerFlag))
                {
                        pDevObj->Timer->TimerFlag = 1;
                        IopTimerCount++;
                }

                __asm
                {
                        sti
                }
        }
}
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
starhust 活跃值 2009-4-13 13:50
15
0
迟来的学习下
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
preboyxt 活跃值 2009-12-3 15:04
16
0
最后一排再挤一个,
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cxlll 活跃值 2009-12-5 11:06
17
0
看下,学习下
雪    币: 126
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
jokersky 活跃值 1 2010-10-28 04:58
18
0
看不懂~
努力学习~
希望有一天可以看懂~
楼主辛苦~
游客
登录 | 注册 方可回帖
返回