參考資訊:
https://wasm.in/
http://four-f.narod.ru/
https://github.com/steward-fu/ddk
main.asm
.386p
.model flat, stdcall
option casemap : none
include c:\masm32\include\w2k\hal.inc
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\include\wxp\csq.inc
include c:\masm32\Macros\Strings.mac
includelib c:\masm32\lib\w2k\hal.lib
includelib c:\masm32\lib\w2k\ntoskrnl.lib
includelib c:\masm32\lib\wxp\i386\csq.lib
public DriverEntry
MyDeviceExtension struct
dpc KDPC <>
csq IO_CSQ <>
timer KTIMER <>
queue LIST_ENTRY <>
locker KSPIN_LOCK <>
pNextDev PDEVICE_OBJECT ?
MyDeviceExtension ends
IOCTL_QUEUE equ CTL_CODE(FILE_DEVICE_UNKNOWN, 800h, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_PROCESS equ CTL_CODE(FILE_DEVICE_UNKNOWN, 801h, METHOD_BUFFERED, FILE_ANY_ACCESS)
.const
MSG_QUEUE byte "IOCTL_QUEUE",0
MSG_PROCESS byte "IOCTL_PROCESS",0
.code
CsqInsertIrp proc uses esi ebx ecx pCsqInfo : PIO_CSQ, pIrp : PIRP
invoke DbgPrint, $CTA0("CsqInsertIrp")
; CONTAINING_RECORD
mov eax, pCsqInfo
sub eax, MyDeviceExtension.csq
mov esi, eax
lea ebx, (MyDeviceExtension ptr [esi]).queue
mov ecx, pIrp
lea ecx, (_IRP ptr [ecx]).Tail.Overlay.ListEntry
InsertTailList ebx, ecx
ret
CsqInsertIrp endp
CsqRemoveIrp proc pCsqInfo : PIO_CSQ, pIrp : PIRP
invoke DbgPrint, $CTA0("CsqRemoveIrp")
mov eax, pIrp
lea eax, (_IRP ptr [eax]).Tail.Overlay.ListEntry
RemoveEntryList eax
ret
CsqRemoveIrp endp
CsqCompleteCanceledIrp proc pCsqInfo : PIO_CSQ, pIrp : PIRP
invoke DbgPrint, $CTA0("CsqCompleteCanceledIrp")
mov eax, pIrp
mov (_IRP ptr [eax]).IoStatus.Status, STATUS_CANCELLED
and (_IRP ptr [eax]).IoStatus.Information, 0
fastcall IofCompleteRequest, eax, IO_NO_INCREMENT
ret
CsqCompleteCanceledIrp endp
CsqPeekNextIrp proc uses esi ebx pCsqInfo : PIO_CSQ, pIrp : PIRP, pPeekContext : PVOID
local nextIrp : PTR _IRP
local listHead : PTR LIST_ENTRY
local nextEntry : PTR LIST_ENTRY
local irpStack : PIO_STACK_LOCATION
invoke DbgPrint, $CTA0("CsqPeekNextIrp")
mov nextIrp, NULL
; CONTAINING_RECORD
mov eax, pCsqInfo
sub eax, MyDeviceExtension.csq
mov esi, eax
lea eax, (MyDeviceExtension ptr [esi]).queue
mov listHead, eax
mov eax, pIrp
.if eax == NULL
mov eax, listHead
push (LIST_ENTRY ptr [eax]).Flink
pop nextEntry
.elseif
mov eax, pIrp
push (_IRP ptr [eax]).Tail.Overlay.ListEntry.Flink
pop nextEntry
.endif
mov eax, nextEntry
mov ebx, listHead
.while eax != ebx
; nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry)
mov eax, nextEntry
sub eax, _IRP.Tail.Overlay.ListEntry
mov nextIrp, eax
IoGetCurrentIrpStackLocation nextIrp
mov irpStack, eax
mov eax, pPeekContext
.if eax == NULL
.break
.endif
mov eax, irpStack
mov eax, (IO_STACK_LOCATION ptr [eax]).FileObject
mov ebx, pPeekContext
.if eax == ebx
.break
.endif
mov nextIrp, NULL
mov eax, nextEntry
mov eax, (LIST_ENTRY ptr [eax]).Flink
mov nextEntry, eax
mov eax, nextEntry
mov ebx, listHead
.endw
mov eax, nextIrp
ret
CsqPeekNextIrp endp
CsqAcquireLock proc uses esi ecx pCsqInfo : PIO_CSQ, pIrql : PKIRQL
invoke DbgPrint, $CTA0("CsqAcquireLock")
; CONTAINING_RECORD
mov eax, pCsqInfo
sub eax, MyDeviceExtension.csq
mov esi, eax
lea ecx, (MyDeviceExtension ptr [esi]).locker
fastcall KfAcquireSpinLock, ecx
mov ecx, pIrql
mov [ecx], al
ret
CsqAcquireLock endp
CsqReleaseLock proc uses esi ecx edx pCsqInfo : PIO_CSQ, Irql : KIRQL
; CONTAINING_RECORD
mov eax, pCsqInfo
sub eax, MyDeviceExtension.csq
mov esi, eax
lea ecx, (MyDeviceExtension PTR [esi]).locker
mov dl, Irql
.if dl == DISPATCH_LEVEL
fastcall KefReleaseSpinLockFromDpcLevel, ecx
push eax
invoke DbgPrint, $CTA0("CsqReleaseLock at DPC level\n")
pop eax
.else
and edx, 0ffh
fastcall KfReleaseSpinLock, ecx, edx
push eax
invoke DbgPrint, $CTA0("CsqReleaseLock at Passive level\n")
pop eax
.endif
ret
CsqReleaseLock endp
OnTimer proc uses esi edi ebx pDpc : PKDPC, pContext : PVOID, pArg1 : PVOID, PArg2 : PVOID
mov eax, pContext
mov esi, (DEVICE_OBJECT ptr [eax]).DeviceExtension
lea edi, (MyDeviceExtension ptr [esi]).queue
IsListEmpty edi
.if eax == TRUE
invoke KeCancelTimer, addr (MyDeviceExtension ptr [esi]).timer
invoke DbgPrint, $CTA0("Finish")
.else
RemoveHeadList edi
; CONTAINING_RECORD
sub eax, _IRP.Tail.Overlay.ListEntry
mov bl, (_IRP PTR [eax]).Cancel
.if bl != TRUE
mov (_IRP PTR [eax]).IoStatus.Status, STATUS_SUCCESS
and (_IRP PTR [eax]).IoStatus.Information, 0
fastcall IofCompleteRequest, eax, IO_NO_INCREMENT
mov eax, STATUS_SUCCESS
invoke DbgPrint, $CTA0("Complete Irp")
.else
mov (_IRP PTR [eax]).CancelRoutine, NULL
mov (_IRP PTR [eax]).IoStatus.Status, STATUS_CANCELLED
and (_IRP PTR [eax]).IoStatus.Information, 0
fastcall IofCompleteRequest, eax, IO_NO_INCREMENT
mov eax, STATUS_CANCELLED
invoke DbgPrint, $CTA0("Cancel Irp")
.endif
.endif
ret
OnTimer endp
IrpOpenClose proc pMyDevie : 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 ebx pMyDevice : PDEVICE_OBJECT, pIrp : PIRP
local period : LARGE_INTEGER
mov eax, pMyDevice
push (DEVICE_OBJECT ptr [eax]).DeviceExtension
pop esi
IoGetCurrentIrpStackLocation pIrp
mov eax, (IO_STACK_LOCATION ptr [eax]).Parameters.DeviceIoControl.IoControlCode
.if eax == IOCTL_QUEUE
invoke DbgPrint, offset MSG_QUEUE
lea ebx, (MyDeviceExtension ptr [esi]).csq
invoke IoCsqInsertIrp, ebx, pIrp, NULL
mov eax, STATUS_PENDING
ret
.elseif eax == IOCTL_PROCESS
invoke DbgPrint, offset MSG_PROCESS
or period.HighPart, -1
mov period.LowPart, -10000000
invoke KeSetTimerEx, addr (MyDeviceExtension ptr [esi]).timer, period.LowPart, period.HighPart, 1000, addr (MyDeviceExtension ptr [esi]).dpc
.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
lea eax, (MyDeviceExtension ptr [eax]).queue
InitializeListHead eax
mov eax, pMyDevice
mov eax, (DEVICE_OBJECT ptr [eax]).DeviceExtension
lea eax, (MyDeviceExtension ptr [eax]).locker
invoke KeInitializeSpinLock, eax
mov eax, pMyDevice
mov eax, (DEVICE_OBJECT ptr [eax]).DeviceExtension
invoke KeInitializeTimer, addr (MyDeviceExtension ptr [eax]).timer
mov eax, pMyDevice
mov eax, (DEVICE_OBJECT ptr [eax]).DeviceExtension
invoke KeInitializeDpc, addr (MyDeviceExtension ptr [eax]).dpc, offset OnTimer, pMyDevice
mov eax, pMyDevice
mov eax, (DEVICE_OBJECT ptr [eax]).DeviceExtension
lea eax, (MyDeviceExtension ptr [eax]).csq
invoke IoCsqInitialize, eax, offset CsqInsertIrp, offset CsqRemoveIrp, offset CsqPeekNextIrp, offset CsqAcquireLock, offset CsqReleaseLock, offset CsqCompleteCanceledIrp
invoke IoCreateSymbolicLink, addr szSymName, addr szDevName
.endif
ret
DriverEntry endp
end DriverEntry
.end
app.asm
.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_QUEUE equ CTL_CODE(FILE_DEVICE_UNKNOWN, 800h, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_PROCESS equ CTL_CODE(FILE_DEVICE_UNKNOWN, 801h, METHOD_BUFFERED, FILE_ANY_ACCESS)
.const
DEV_NAME db "\\.\MyDriver",0
.data?
cnt dd ?
hFile dd ?
dwRet dd ?
event dd 3 dup(?)
ov OVERLAPPED <?>
.code
start:
invoke CreateFile, offset DEV_NAME, GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL, 0
mov hFile, eax
invoke crt_memset, offset ov, 0, sizeof OVERLAPPED
mov cnt, 3
.while cnt > 0
invoke CreateEvent, NULL, TRUE, FALSE, NULL
push eax
pop ov.hEvent
mov ecx, cnt
mov edi, offset event
mov [edi + ecx * 4], eax
invoke crt_printf, $CTA0("Queued event\n")
invoke DeviceIoControl, hFile, IOCTL_QUEUE, NULL, 0, NULL, 0, offset dwRet, offset ov
invoke CloseHandle, ov.hEvent
sub cnt, 1
.endw
invoke crt_printf, $CTA0("Processing All Events\n")
invoke DeviceIoControl, hFile, IOCTL_PROCESS, NULL, 0, NULL, 0, offset dwRet, NULL
invoke Sleep, 1000
invoke CancelIo, hFile
mov cnt, 3
.while cnt > 0
mov ecx, cnt
mov edi, offset event
mov eax, [edi + ecx * 4]
push eax
pop ov.hEvent
invoke WaitForSingleObject, ov.hEvent, INFINITE
invoke CloseHandle, ov.hEvent
invoke crt_printf, $CTA0("Complete\n")
sub cnt, 1
.endw
invoke CloseHandle, hFile
invoke ExitProcess, 0
end start
.end
結果
