驅動程式 - Windows NT Driver (Legacy) - 使用範例 - Assembly (MASM32) - Use DPC Timer



參考資訊:
https://wasm.in/
http://four-f.narod.ru/
https://github.com/steward-fu/ddk

由於I/O Timer的Timer間隔固定為一秒,如果想要可以彈性設定的Timer間隔,需要使用DPC Timer,使用的步驟如下:

1. KeInitializeTimer()
2. KeInitializeDpc()
3. KeSetTimer()
4. KeCancelTimer()

DPC Timer如果使用KeSetTimer()做設定時,其Timer為一次性,也就是Callback僅會被呼叫一次,如果要使用週期性Timer,則需要改用KeSetTimerEx(),KeSetTimerEx()宣告如下:

BOOLEAN KeSetTimerEx(PKTIMER Timer, LARGE_INTEGER DueTime, LONG Period, PKDPC Dpc);

DueTime是第一次Timer的間隔,之後的間隔則使用Period數值

main.asm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
.386p
.model flat, stdcall
option casemap:none
     
include c:\masm32\include\w2k\ntstatus.inc
include c:\masm32\include\w2k\ntddk.inc
include c:\masm32\include\w2k\ntoskrnl.inc
include c:\masm32\include\w2k\ntddkbd.inc
include c:\masm32\Macros\Strings.mac
 
includelib c:\masm32\lib\wxp\i386\ntoskrnl.lib
  
public DriverEntry
  
MyDeviceExtension struct
    cnt DWORD ?
    dpc KDPC <>
    obj KTIMER <>
    pNextDev PDEVICE_OBJECT ?
MyDeviceExtension ends
  
IOCTL_START equ CTL_CODE(FILE_DEVICE_UNKNOWN, 800h, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_STOP  equ CTL_CODE(FILE_DEVICE_UNKNOWN, 801h, METHOD_BUFFERED, FILE_ANY_ACCESS)
  
.const
MSG_START byte "IOCTL_START",0
MSG_STOP  byte "IOCTL_STOP",0
  
.code
OnTimer proc uses esi pDpc : PKDPC, pContext : PVOID, pArg1 : PVOID, PArg2 : PVOID
    mov eax, pContext
    mov esi, (DEVICE_OBJECT ptr [eax]).DeviceExtension
    inc (MyDeviceExtension ptr[esi]).cnt
    invoke DbgPrint, $CTA0("DpcTimer: %d\n"), (MyDeviceExtension ptr[esi]).cnt
    ret
OnTimer endp
  
IrpOpenClose proc pMyDevice : PDEVICE_OBJECT, pIrp : PIRP
    IoGetCurrentIrpStackLocation pIrp
    movzx eax, (IO_STACK_LOCATION ptr [eax]).MajorFunction
 
    .if eax == IRP_MJ_CREATE
        invoke DbgPrint, $CTA0("IRP_MJ_CREATE")
    .elseif eax == IRP_MJ_CLOSE
        invoke DbgPrint, $CTA0("IRP_MJ_CLOSE")
    .endif
  
    mov eax, pIrp
    and (_IRP ptr [eax]).IoStatus.Information, 0
    mov (_IRP ptr [eax]).IoStatus.Status, STATUS_SUCCESS
    fastcall IofCompleteRequest, pIrp, IO_NO_INCREMENT
    mov eax, STATUS_SUCCESS
    ret
IrpOpenClose endp
  
IrpIOCTL proc uses esi pMyDevice : PDEVICE_OBJECT, pIrp : PIRP
    local hThread : DWORD
    local pThread : PVOID
    local cnt : LARGE_INTEGER
 
    mov eax, pMyDevice
    mov esi, (DEVICE_OBJECT ptr [eax]).DeviceExtension
 
    IoGetCurrentIrpStackLocation pIrp
    mov eax, (IO_STACK_LOCATION ptr [eax]).Parameters.DeviceIoControl.IoControlCode
    .if eax == IOCTL_START
        invoke DbgPrint, offset MSG_START
          
        or cnt.HighPart, -1
        mov cnt.LowPart, -10000000
        and (MyDeviceExtension ptr[esi]).cnt, 0
          
        invoke KeSetTimerEx, addr (MyDeviceExtension ptr[esi]).obj, cnt.LowPart, cnt.HighPart, 1000, addr (MyDeviceExtension ptr[esi]).dpc
    .elseif eax == IOCTL_STOP
        invoke DbgPrint, offset MSG_STOP
        invoke KeCancelTimer, addr (MyDeviceExtension ptr[esi]).obj
    .endif
  
    mov eax, pIrp
    mov (_IRP ptr [eax]).IoStatus.Status, STATUS_SUCCESS
    and (_IRP ptr [eax]).IoStatus.Information, 0
    fastcall IofCompleteRequest, pIrp, IO_NO_INCREMENT
    mov eax, STATUS_SUCCESS
    ret
IrpIOCTL endp
  
Unload proc pMyDriver : PDRIVER_OBJECT
    local szSymName : UNICODE_STRING
                             
    invoke RtlInitUnicodeString, addr szSymName, $CTW0("\\DosDevices\\MyDriver")
    invoke IoDeleteSymbolicLink, addr szSymName
                             
    mov eax, pMyDriver
    invoke IoDeleteDevice, (DRIVER_OBJECT ptr [eax]).DeviceObject
    ret
Unload endp
              
DriverEntry proc pMyDriver : PDRIVER_OBJECT, pMyRegistry : PUNICODE_STRING
    local pMyDevice : PDEVICE_OBJECT
    local szDevName : UNICODE_STRING
    local szSymName : UNICODE_STRING
                  
    mov eax, pMyDriver
    mov (DRIVER_OBJECT ptr [eax]).MajorFunction[IRP_MJ_CREATE * (sizeof PVOID)], offset IrpOpenClose
    mov (DRIVER_OBJECT ptr [eax]).MajorFunction[IRP_MJ_CLOSE * (sizeof PVOID)], offset IrpOpenClose
    mov (DRIVER_OBJECT ptr [eax]).MajorFunction[IRP_MJ_DEVICE_CONTROL * (sizeof PVOID)], offset IrpIOCTL
    mov (DRIVER_OBJECT ptr [eax]).DriverUnload, offset Unload
                  
    invoke RtlInitUnicodeString, addr szDevName, $CTW0("\\Device\\MyDriver")
    invoke RtlInitUnicodeString, addr szSymName, $CTW0("\\DosDevices\\MyDriver")
 
    invoke IoCreateDevice, pMyDriver, sizeof MyDeviceExtension, addr szDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, addr pMyDevice
    .if eax == STATUS_SUCCESS
        mov eax, pMyDevice
        or (DEVICE_OBJECT ptr [eax]).Flags, DO_BUFFERED_IO
        and (DEVICE_OBJECT ptr [eax]).Flags, not DO_DEVICE_INITIALIZING
        mov eax, pMyDevice
        mov eax, (DEVICE_OBJECT ptr [eax]).DeviceExtension
        invoke KeInitializeTimer, addr (MyDeviceExtension ptr [eax]).obj
  
        mov eax, pMyDevice
        mov eax, (DEVICE_OBJECT ptr [eax]).DeviceExtension
        invoke KeInitializeDpc, addr (MyDeviceExtension ptr [eax]).dpc, offset OnTimer, pMyDevice
        invoke IoCreateSymbolicLink, addr szSymName, addr szDevName
    .endif
    ret
DriverEntry endp
end DriverEntry
.end

app.asm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
.386p
.model flat, stdcall
option casemap:none
     
include c:\masm32\include\windows.inc
include c:\masm32\include\masm32.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\msvcrt.inc
include c:\masm32\include\kernel32.inc
include c:\masm32\include\w2k\ntddkbd.inc
include c:\masm32\Macros\Strings.mac
      
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\masm32.lib
includelib c:\masm32\lib\msvcrt.lib
includelib c:\masm32\lib\kernel32.lib
     
IOCTL_START equ CTL_CODE(FILE_DEVICE_UNKNOWN, 800h, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_STOP  equ CTL_CODE(FILE_DEVICE_UNKNOWN, 801h, METHOD_BUFFERED, FILE_ANY_ACCESS)
     
.const
DEV_NAME db "\\.\MyDriver",0
     
.data?
hFile dd ?
dwRet dd ?
     
.code
start:
    invoke CreateFile, offset DEV_NAME, GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
    mov hFile, eax
         
    invoke DeviceIoControl, hFile, IOCTL_START, NULL, 0, NULL, 0, offset dwRet, NULL
    invoke Sleep, 3000
    invoke DeviceIoControl, hFile, IOCTL_STOP, NULL, 0, NULL, 0, offset dwRet, NULL
  
    invoke CloseHandle, hFile
    invoke ExitProcess, 0
end start

完成