// @doc /********************************************************************** * * @module GckShell.c | * * Basic driver entry points for GcKernel.sys * * History * ---------------------------------------------------------- * Mitchell S. Dernis Original * * (c) 1986-1998 Microsoft Corporation. All right reserved. * * @topic GckShell | * Contains the most basic driver entry points (that any NT\WDM driver * would have) for GcKernel.sys. * **********************************************************************/ #define __DEBUG_MODULE_IN_USE__ GCK_GCKSHELL_C #include #include "Debug.h" #include "GckShell.h" #include "vmmid.h" #ifdef BUILD_98 extern void* KeyBoardHook(void); #endif // // Mark the pageable routines as such // #ifdef ALLOC_PRAGMA #pragma alloc_text (INIT, DriverEntry) #pragma alloc_text (PAGE, GCK_Create) #pragma alloc_text (PAGE, GCK_Close) #pragma alloc_text (PAGE, GCK_Unload) #endif // // Allow debug output for this moduel, and set the intial level // DECLARE_MODULE_DEBUG_LEVEL((DBG_WARN|DBG_ERROR|DBG_CRITICAL)); // // Instance the global variables // GCK_GLOBALS Globals; ULONG ulWaitTime = 30; #ifdef BUILD_98 #pragma data_seg("_LDATA", "LCODE") LONG g_lHookRefCount = 0; ULONG g_rgdwKeyEvents[50] = { 0 }; ULONG g_pPreviousKeyhook = 0; UCHAR g_ucWriteIndex = 0; UCHAR g_ucReadIndex = 0; #pragma data_seg() #pragma code_seg("_LTEXT", "LCODE") #endif BUILD_98 void KeyHookC(ULONG dwScanCode) { #ifdef BUILD_98 g_rgdwKeyEvents[g_ucWriteIndex++] = dwScanCode; if (g_ucWriteIndex >= 50) { g_ucWriteIndex = 0; } #else !BUILD_98 UNREFERENCED_PARAMETER (dwScanCode); #endif BUILD_98 } #ifdef BUILD_98 //----------------------------------------------------------------------------- // InitHook - Sets up the keyboard hook //----------------------------------------------------------------------------- BOOLEAN HookKeyboard(void) { volatile ULONG dwHook = (ULONG)KeyBoardHook; RtlZeroMemory((void*)g_rgdwKeyEvents, sizeof(ULONG) * 50); g_ucWriteIndex = 0; g_ucReadIndex = 0; // GetVxDServiceOrdinal eax, VKD_Filter_Keyboard_Input __asm mov eax, __VKD_Filter_Keyboard_Input __asm mov esi, dwHook VxDCall(__Hook_Device_Service) __asm jc initfail __asm mov [g_pPreviousKeyhook], esi // Since we are using C we can't use the funky callback return TRUE; initfail: return FALSE; }; #pragma code_seg() void UnHookKeyboard() { volatile ULONG dwHook = (ULONG)KeyBoardHook; // GetVxDServiceOrdinal eax, VKD_Filter_Keyboard_Input __asm mov eax, __VKD_Filter_Keyboard_Input __asm mov esi, dwHook VxDCall(__Unhook_Device_Service) __asm clc } #endif BUILD_98 /*********************************************************************************** ** ** NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ) ** ** @func Standard DriverEntry routine ** ** @rdesc STATUS_SUCCESS or various errors ** *************************************************************************************/ NTSTATUS DriverEntry ( IN PDRIVER_OBJECT pDriverObject, // @parm Driver Object IN PUNICODE_STRING puniRegistryPath // @parm Path to driver specific registry section. ) { NTSTATUS NtStatus = STATUS_SUCCESS; int i; UNREFERENCED_PARAMETER (puniRegistryPath); PAGED_CODE(); GCK_DBG_CRITICAL_PRINT(("Built %s at %s\n", __DATE__, __TIME__)); GCK_DBG_CRITICAL_PRINT(("Entering DriverEntry, pDriverObject = 0x%0.8x, puniRegistryPath = %s\n", pDriverObject, puniRegistryPath)); // Allow Control Device module to initialize itself NtStatus = GCK_CTRL_DriverEntry(pDriverObject, puniRegistryPath); if( NT_ERROR(NtStatus) ) { return NtStatus; } // Allow Filter Device module to initialize itself NtStatus = GCK_FLTR_DriverEntry(pDriverObject, puniRegistryPath); if( NT_ERROR(NtStatus) ) { return NtStatus; } // Allow SideWinder Virtual Bus module to initialize itself NtStatus = GCK_SWVB_DriverEntry(pDriverObject, puniRegistryPath); if( NT_ERROR(NtStatus) ) { return NtStatus; } // Allow SideWinder Virtual Keyboard module to initialize itself NtStatus = GCK_VKBD_DriverEntry(pDriverObject, puniRegistryPath); if( NT_ERROR(NtStatus) ) { return NtStatus; } // Hook all IRPs so we can pass them on. GCK_DBG_TRACE_PRINT(("Filling out entry point structure\n")); for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { pDriverObject->MajorFunction[i] = GCK_Pass; } // Initialize any shared global data #ifdef BUILD_98 g_lHookRefCount = 0; #endif // Define entries for IRPs we expect to handle pDriverObject->MajorFunction[IRP_MJ_CREATE] = GCK_Create; pDriverObject->MajorFunction[IRP_MJ_CLOSE] = GCK_Close; pDriverObject->MajorFunction[IRP_MJ_READ] = GCK_Read; pDriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = GCK_Ioctl; pDriverObject->MajorFunction[IRP_MJ_PNP] = GCK_PnP; pDriverObject->MajorFunction[IRP_MJ_POWER] = GCK_Power; pDriverObject->DriverExtension->AddDevice = GCK_FLTR_AddDevice; //only the filter has an add device pDriverObject->DriverUnload = GCK_Unload; GCK_DBG_EXIT_PRINT (("Normal exit of DriverEntry: 0x%0.8x\n", NtStatus)); return NtStatus; } /*********************************************************************************** ** ** VOID GCK_Unload(IN PDRIVER_OBJECT pDriverObject ) ** ** @func Called to unload driver, delete Control Device here ** *************************************************************************************/ VOID GCK_Unload ( IN PDRIVER_OBJECT pDriverObject // @parm Driver Object for our driver ) { PAGED_CODE (); GCK_DBG_ENTRY_PRINT(("Entering GCK_Unload, pDriverObject = 0x%0.8x\n", pDriverObject)); UNREFERENCED_PARAMETER(pDriverObject); GCK_SWVB_UnLoad(); // // We should not be unloaded until all the PDOs have been removed from // our queue. The control device object should be the only thing left. // ASSERT (NULL == pDriverObject->DeviceObject); ASSERT (NULL == Globals.pControlObject); GCK_DBG_EXIT_PRINT(("Exiting GCK_Unload\n")); return; } /*********************************************************************************** ** ** NTSTATUS GCK_Create ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) ** ** @func Handles the IRP_MJ_CREATE - Generated by Win32 CreateFile or OpenFile ** ** @rdesc STATUS_SUCCESS, or various error codes ** *************************************************************************************/ NTSTATUS GCK_Create ( IN PDEVICE_OBJECT pDeviceObject, // @parm Device Object for context of IRP IN PIRP pIrp // @parm pointer to IRP ) { NTSTATUS NtStatus; ULONG ulGckDevObjType; PAGED_CODE (); GCK_DBG_ENTRY_PRINT (("GCK_Create, pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp)); KdPrint(("GCK_Create, pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp)); ulGckDevObjType = *(PULONG)pDeviceObject->DeviceExtension; switch(ulGckDevObjType) { case GCK_DO_TYPE_CONTROL: KdPrint((" -- GCK_DO_TYPE_CONTROL\n")); NtStatus = GCK_CTRL_Create(pDeviceObject, pIrp); break; case GCK_DO_TYPE_FILTER: KdPrint((" -- GCK_DO_TYPE_FILTER\n")); NtStatus = GCK_FLTR_Create(pDeviceObject, pIrp); break; case GCK_DO_TYPE_SWVB: KdPrint((" -- GCK_DO_TYPE_SWVB\n")); NtStatus = GCK_SWVB_Create(pDeviceObject, pIrp); break; default: // // If this assertion is hit, this Device Object was never properly initialized // by GcKernel, or it has been trashed. // ASSERT(FALSE); NtStatus = STATUS_UNSUCCESSFUL; IoCompleteRequest (pIrp, IO_NO_INCREMENT); } GCK_DBG_EXIT_PRINT(("Exiting GCK_Create. Status: 0x%0.8x\n", NtStatus)); KdPrint(("Exiting GCK_Create. Status: 0x%0.8x\n", NtStatus)); return NtStatus; } /*********************************************************************************** ** ** NTSTATUS GCK_Close ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) ** ** @func Handles IRP_MJ_CLOSE - Generated by Win32 CloseFile ** ** @rdesc STATUS_SUCCESS or various errors ** *************************************************************************************/ NTSTATUS GCK_Close ( IN PDEVICE_OBJECT pDeviceObject, // @parm pointer DeviceObject for context IN PIRP pIrp // @parm pointer to IRP to handle ) { NTSTATUS NtStatus; ULONG ulGckDevObjType = *(PULONG)pDeviceObject->DeviceExtension; PAGED_CODE (); GCK_DBG_ENTRY_PRINT (("GCK_Close, pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp)); ulGckDevObjType = *(PULONG)pDeviceObject->DeviceExtension; switch(ulGckDevObjType) { case GCK_DO_TYPE_CONTROL: NtStatus = GCK_CTRL_Close(pDeviceObject, pIrp); break; case GCK_DO_TYPE_FILTER: NtStatus = GCK_FLTR_Close(pDeviceObject, pIrp); break; case GCK_DO_TYPE_SWVB: NtStatus = GCK_SWVB_Close(pDeviceObject, pIrp); break; default: // // If this assertion is hit, this Device Object was never properly initialized // by GcKernel, or it has been trashed. // ASSERT(FALSE); NtStatus = STATUS_UNSUCCESSFUL; } GCK_DBG_EXIT_PRINT(("Exiting GCK_Close. Status: 0x%0.8x\n", NtStatus)); return NtStatus; } /*********************************************************************************** ** ** NTSTATUS GCK_Read (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) ** ** @func Handles IRP_MJ_READ - Generated by Win32 ReadFile ** ** @rdesc STATUS_SUCCESS, or various errors ** *************************************************************************************/ NTSTATUS GCK_Read ( IN PDEVICE_OBJECT pDeviceObject, // @parm Device Object as our context IN PIRP pIrp // @parm IRP to handle ) { NTSTATUS NtStatus; ULONG ulGckDevObjType; GCK_DBG_RT_ENTRY_PRINT(("Entering GCK_Read. pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp)); ulGckDevObjType = *(PULONG)pDeviceObject->DeviceExtension; switch(ulGckDevObjType) { case GCK_DO_TYPE_CONTROL: NtStatus = STATUS_NOT_SUPPORTED; //Assert as we shouldn't get read on the control device ASSERT( NT_SUCCESS(NtStatus) ); IoCompleteRequest (pIrp, IO_NO_INCREMENT); break; case GCK_DO_TYPE_FILTER: NtStatus = GCK_FLTR_Read(pDeviceObject, pIrp); break; case GCK_DO_TYPE_SWVB: NtStatus = GCK_SWVB_Read(pDeviceObject, pIrp); break; default: // // If this assertion is hit, this Device Object was never properly initialized // by GcKernel, or it has been trashed. // ASSERT(FALSE); IoCompleteRequest (pIrp, IO_NO_INCREMENT); NtStatus = STATUS_UNSUCCESSFUL; } GCK_DBG_EXIT_PRINT(("Exiting GCK_Read. Status: 0x%0.8x\n", NtStatus)); return NtStatus; } /*********************************************************************************** ** ** NTSTATUS GCK_Power (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) ** ** @func Handles IRP_MJ_POWER ** ** @rdesc STATUS_SUCCESS, or various errors ** *************************************************************************************/ NTSTATUS GCK_Power ( IN PDEVICE_OBJECT pDeviceObject, // @parm Device Object for our context IN PIRP pIrp // @parm IRP to handle ) { NTSTATUS NtStatus; ULONG ulGckDevObjType; GCK_DBG_ENTRY_PRINT(("Entering GCK_Power. pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp)); ulGckDevObjType = *(PULONG)pDeviceObject->DeviceExtension; switch(ulGckDevObjType) { case GCK_DO_TYPE_CONTROL: NtStatus = STATUS_NOT_SUPPORTED; //Assert as we shouldn't get power on the control device ASSERT( NT_SUCCESS(NtStatus) ); IoCompleteRequest(pIrp, IO_NO_INCREMENT); break; case GCK_DO_TYPE_FILTER: NtStatus = GCK_FLTR_Power(pDeviceObject, pIrp); break; case GCK_DO_TYPE_SWVB: NtStatus = GCK_SWVB_Power(pDeviceObject, pIrp); break; default: // // If this assertion is hit, this Device Object was never properly initialized // by GcKernel, or it has been trashed. // ASSERT(FALSE); IoCompleteRequest (pIrp, IO_NO_INCREMENT); NtStatus = STATUS_UNSUCCESSFUL; } GCK_DBG_EXIT_PRINT(("Exiting GCK_Power. Status: 0x%0.8x\n", NtStatus)); return NtStatus; } /*********************************************************************************** ** ** NTSTATUS GCK_PnP (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) ** ** @func Handles IRP_MJ_PnP ** ** @rdesc STATUS_SUCCESS, or various errors ** *************************************************************************************/ NTSTATUS GCK_PnP ( IN PDEVICE_OBJECT pDeviceObject, // @parm Device Object for our context IN PIRP pIrp // @parm IRP to handle ) { NTSTATUS NtStatus; ULONG ulGckDevObjType; GCK_DBG_ENTRY_PRINT(("Entering GCK_PnP. pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp)); ulGckDevObjType = *(PULONG)pDeviceObject->DeviceExtension; switch(ulGckDevObjType) { case GCK_DO_TYPE_CONTROL: NtStatus = STATUS_NOT_SUPPORTED; //Assert as we shouldn't get PnP on the control device ASSERT( NT_SUCCESS(NtStatus) ); pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT); break; case GCK_DO_TYPE_FILTER: NtStatus = GCK_FLTR_PnP(pDeviceObject, pIrp); break; case GCK_DO_TYPE_SWVB: NtStatus = GCK_SWVB_PnP(pDeviceObject, pIrp); break; default: // // If this assertion is hit, this Device Object was never properly initialized // by GcKernel, or it has been trashed. // ASSERT(FALSE); IoCompleteRequest (pIrp, IO_NO_INCREMENT); NtStatus = STATUS_UNSUCCESSFUL; } GCK_DBG_EXIT_PRINT(("Exiting GCK_PnP. Status: 0x%0.8x\n", NtStatus)); return NtStatus; } /*********************************************************************************** ** ** NTSTATUS GCK_Ioctl (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) ** ** @func Handles IRP_MJ_IOCTL and IRP_MJ_INTERNAL_IOCTL ** ** @rdesc STATUS_SUCCES, or various errors ** *************************************************************************************/ NTSTATUS GCK_Ioctl ( IN PDEVICE_OBJECT pDeviceObject, // @parm pointer to Device Object IN PIRP pIrp // @parm pointer to IRP ) { NTSTATUS NtStatus; ULONG ulGckDevObjType; ULONG uIoctl; PIO_STACK_LOCATION pIrpStack; GCK_DBG_ENTRY_PRINT(("Entering GCK_Ioctl. pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp)); pIrpStack = IoGetCurrentIrpStackLocation(pIrp); uIoctl = pIrpStack->Parameters.DeviceIoControl.IoControlCode; if (uIoctl == IOCTL_GCK_ENABLE_KEYHOOK) { // Special case IOCTL, device independant #ifdef BUILD_WIN2K pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; #else !BUILD_WIN2K if (InterlockedIncrement(&g_lHookRefCount) == 1) { // Not already hooked HookKeyboard(); } pIrp->IoStatus.Status = STATUS_SUCCESS; #endif BUILD_WIN2K IoCompleteRequest (pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; } if (uIoctl == IOCTL_GCK_DISABLE_KEYHOOK) { // Special case also device independant #ifdef BUILD_WIN2K pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; #else !BUILD_WIN2K if (InterlockedDecrement(&g_lHookRefCount) < 1) { // Last hooker is going away UnHookKeyboard(); g_lHookRefCount = 0; } pIrp->IoStatus.Status = STATUS_SUCCESS; #endif BUILD_WIN2K IoCompleteRequest (pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; } if (uIoctl == IOCTL_GCK_GET_KEYHOOK_DATA) { #ifdef BUILD_WIN2K NtStatus = STATUS_UNSUCCESSFUL; #else !BUILD_WIN2K ULONG uOutLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength; if (uOutLength < sizeof(ULONG)) { NtStatus = STATUS_BUFFER_TOO_SMALL; } else { ULONG* pulIoBuffer = (ULONG*)(pIrp->AssociatedIrp.SystemBuffer); *pulIoBuffer = 0; pIrp->IoStatus.Information = sizeof(ULONG); NtStatus = STATUS_SUCCESS; if (g_lHookRefCount > 0) { // There is a hook if (g_ucWriteIndex != g_ucReadIndex) { // We have data in the Queue *pulIoBuffer = g_rgdwKeyEvents[g_ucReadIndex++]; if (g_ucReadIndex >= 50) { g_ucReadIndex = 0; } } } } #endif BUILD_WIN2K pIrp->IoStatus.Status = NtStatus; IoCompleteRequest (pIrp, IO_NO_INCREMENT); return NtStatus; } ulGckDevObjType = *(PULONG)pDeviceObject->DeviceExtension; switch(ulGckDevObjType) { case GCK_DO_TYPE_CONTROL: NtStatus = GCK_CTRL_Ioctl(pDeviceObject, pIrp); break; case GCK_DO_TYPE_FILTER: NtStatus = GCK_FLTR_Ioctl(pDeviceObject, pIrp); break; case GCK_DO_TYPE_SWVB: NtStatus = GCK_SWVB_Ioctl(pDeviceObject, pIrp); break; default: // // If this assertion is hit, this Device Object was never properly initialized // by GcKernel, or it has been trashed. // ASSERT(FALSE); IoCompleteRequest (pIrp, IO_NO_INCREMENT); NtStatus = STATUS_UNSUCCESSFUL; } GCK_DBG_EXIT_PRINT(("Exiting GCK_Ioctl. Status: 0x%0.8x\n", NtStatus)); return NtStatus; } /*********************************************************************************** ** ** NTSTATUS GCK_Pass ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) ** ** @func Passes on unhandled IRPs to lower drivers DEBUG version trace out info ** Cannot be pageable since we have no idea what IRPs we're getting. ** ** @rdesc STATUS_SUCCESS, various errors ** *************************************************************************************/ NTSTATUS GCK_Pass ( IN PDEVICE_OBJECT pDeviceObject, // @parm Device Object as our context IN PIRP pIrp // @parm IRP to pass on ) { NTSTATUS NtStatus; ULONG ulGckDevObjType; PGCK_FILTER_EXT pFilterExt; // Debug version want IRP stack for traceouts. #if (DBG==1) PIO_STACK_LOCATION pIrpStack; pIrpStack = IoGetCurrentIrpStackLocation(pIrp); #endif GCK_DBG_ENTRY_PRINT(("Entering GCK_Pass. pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp)); GCK_DBG_TRACE_PRINT( ( "GCK_Pass called with Irp MajorFunction = 0x%0.8x, MinorFunction = 0x%0.8x\n", pIrpStack->MajorFunction, pIrpStack->MinorFunction) ); ulGckDevObjType = *(PULONG)pDeviceObject->DeviceExtension; switch(ulGckDevObjType) { case GCK_DO_TYPE_FILTER: GCK_DBG_TRACE_PRINT(( "Passing IRP to lower driver\n")); pFilterExt = (PGCK_FILTER_EXT)pDeviceObject->DeviceExtension; IoSkipCurrentIrpStackLocation (pIrp); NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp); break; case GCK_DO_TYPE_CONTROL: case GCK_DO_TYPE_SWVB: // No one to pass to, so return default status NtStatus = pIrp->IoStatus.Status; IoCompleteRequest (pIrp, IO_NO_INCREMENT); break; default: // // If this assertion is hit, this Device Object was never properly initialized // by GcKernel, or it has been trashed. // ASSERT(FALSE); NtStatus = STATUS_UNSUCCESSFUL; pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest (pIrp, IO_NO_INCREMENT); }; //return GCK_DBG_EXIT_PRINT(("Exiting GCK_Pass. Status: 0x%0.8x\n", NtStatus)); return NtStatus; }