Listing 4: sigdrv.c Kernel-mode driver for signal library
#define STRICT 1 #include "ntddk.h" #include "string.h" #include "sigdrv.h" #define SIGDRV_DEVICE_NAME_U L"\\Device\\Sigdrv" #define SIGDRV_DOS_DEVICE_NAME_U L"\\DosDevices\\SIGDRV" // Debugging macros #ifdef DBG #define SigDrvKdPrint(_x_) \ DbgPrint("SigDrv.sys: ");\ DbgPrint _x_; #else #define SigDrvKdPrint(_x_) #endif NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING registryPath); VOID SigDrvUnload( IN PDRIVER_OBJECT DriverObject); NTSTATUS SigDrvDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS SigDrvSendTheSignal( IN PDEVICE_OBJECT DeviceObject, IN OUT PVOID ioBuffer, IN ULONG inputBufferLength, IN ULONG outputBufferLength); void KeInitializeApc( PKAPC Apc, PKTHREAD Thread, CCHAR ApcStateIndex, PKKERNEL_ROUTINE KernelRoutine, PKRUNDOWN_ROUTINE RundownRoutine, PKNORMAL_ROUTINE NormalRoutine, KPROCESSOR_MODE ApcMode, PVOID NormalContext); void KeInsertQueueApc( PKAPC Apc, PVOID SystemArgument1, PVOID SystemArgument2, UCHAR unknown); // Information the driver receives from user mode typedef struct _SIGINFO { HANDLE hThread; // handle of targer thread ULONG SigNo; // which signal ULONG SigFunc; // signals' driver-routine of the dll } SIGINFO, *PSIGINFO; void KernelApcCallBack( PKAPC Apc, PKNORMAL_ROUTINE NormalRoutine, PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) { ExFreePool(Apc); // just free the kernel memory return; } void UserApcCallBack(PVOID arg1, PVOID arg2, PVOID arg3) { PSIGINFO psiginfo = (PSIGINFO) arg3; ULONG (*SignalDriverRoutine)(ULONG); // take the user mode address of the function SignalDriverRoutine = (unsigned long (__stdcall *) (unsigned long)) psiginfo->SigFunc; // call the driver-routine SignalDriverRoutine(psiginfo->SigNo); return; } NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { PDEVICE_OBJECT deviceObject=NULL; NTSTATUS ntStatus; WCHAR deviceNameBuffer[]=SIGDRV_DEVICE_NAME_U; UNICODE_STRING deviceNameUnicodeString; WCHAR deviceLinkBuffer[]=SIGDRV_DOS_DEVICE_NAME_U; UNICODE_STRING deviceLinkUnicodeString; RtlInitUnicodeString (&deviceNameUnicodeString, deviceNameBuffer); ntStatus = IoCreateDevice ( DriverObject,0,&deviceNameUnicodeString, FILE_DEVICE_SIGDRV,0,FALSE,&deviceObject); if (!NT_SUCCESS(ntStatus)) { SigDrvKdPrint(("IoCreateDevice failed:%x\n", ntStatus)); return ntStatus; } DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverObject->MajorFunction[IRP_MJ_CLOSE] = SigDrvDispatch; DriverObject->DriverUnload = SigDrvUnload; RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer); ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString, &deviceNameUnicodeString); if (!NT_SUCCESS(ntStatus)) { SigDrvKdPrint (("IoCreateSymbolicLink failed\n")); IoDeleteDevice (deviceObject); } return ntStatus; } NTSTATUS SigDrvDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION irpStack; PVOID ioBuffer; ULONG inputBufferLength; ULONG outputBufferLength; ULONG ioControlCode; NTSTATUS ntStatus; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; irpStack = IoGetCurrentIrpStackLocation(Irp); ioBuffer = Irp->AssociatedIrp.SystemBuffer; inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength; outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; switch (irpStack->MajorFunction) { case IRP_MJ_CREATE: SigDrvKdPrint (("IRP_MJ_CREATE\n")); break; case IRP_MJ_CLOSE: SigDrvKdPrint (("IRP_MJ_CLOSE\n")); break; case IRP_MJ_DEVICE_CONTROL: ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; switch (ioControlCode) { case IOCTL_SIGDRV_SEND_SIGNAL: Irp->IoStatus.Status = SigDrvSendTheSignal( DeviceObject, ioBuffer, inputBufferLength, outputBufferLength); if (NT_SUCCESS(Irp->IoStatus.Status)) { Irp->IoStatus.Information = sizeof(PVOID); SigDrvKdPrint(("Signal was sent\n")); } else { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; SigDrvKdPrint(("Signal failed to be sent\n")); } break; default: SigDrvKdPrint (("unknown IRP_MJ_DEVICE_CONTROL\n")); Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; break; } break; } ntStatus = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return ntStatus; } VOID SigDrvUnload(IN PDRIVER_OBJECT DriverObject) { WCHAR deviceLinkBuffer[] = SIGDRV_DOS_DEVICE_NAME_U; UNICODE_STRING deviceLinkUnicodeString; RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer); IoDeleteSymbolicLink (&deviceLinkUnicodeString); IoDeleteDevice (DriverObject->DeviceObject); return; } NTSTATUS SigDrvSendTheSignal( IN PDEVICE_OBJECT DeviceObject, IN OUT PVOID IoBuffer, IN ULONG InputBufferLength, IN ULONG OutputBufferLength) { NTSTATUS ntStatus = STATUS_SUCCESS; PVOID virtualAddress; SIGINFO *psiginfo = (PSIGINFO) IoBuffer; PETHREAD uThread = NULL; PKAPC kApc; // take a pointer to the kernel thread structure ntStatus = ObReferenceObjectByHandle( psiginfo->hThread, THREAD_ALL_ACCESS, NULL, KernelMode, &uThread, NULL); if (NT_ERROR(ntStatus)) { SigDrvKdPrint (("ObReferenceObjectByHandle Failed\n")); return ntStatus; } // Allocate an KAPC structure from NonPagedPool kApc = ExAllocatePool(NonPagedPool, sizeof(KAPC)); KeInitializeApc(kApc, (PKTHREAD) uThread, 0, (PKKERNEL_ROUTINE) &KernelApcCallBack, 0, (PKNORMAL_ROUTINE) &UserApcCallBack, KernelMode, (PVOID) 0); KeInsertQueueApc (kApc, (PVOID) (ULONG) 10, (PVOID) psiginfo, 0); ObDereferenceObject((PVOID) uThread); return ntStatus; } /* End of File */