NTSTATUS wddDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { UNICODE_STRING DestinationPath; PIO_STACK_LOCATION IrpStack; NTSTATUS status = STATUS_INVALID_PARAMETER; ULONG IoControlCode; PVOID IoBuffer; PULONG OutputBuffer; PDEVICE_EXTENSION ext; ULONG InputLen, OutputLen; ULONG Level; ULONG Type; // We must be running in PASSIVE_LEVEL or we bluescreen here. We // theoretically should always be running at PASSIVE_LEVEL here, but // in case we ended up here at the wrong IRQL its better to bail // than to bluescreen. if(KeGetCurrentIrql() != PASSIVE_LEVEL) { status = STATUS_ABANDONED; goto exit; }; ext = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; Irp->IoStatus.Information = 0; IrpStack = IoGetCurrentIrpStackLocation(Irp); IoBuffer = Irp->AssociatedIrp.SystemBuffer; OutputLen = IrpStack->Parameters.DeviceIoControl.OutputBufferLength; InputLen = IrpStack->Parameters.DeviceIoControl.InputBufferLength; IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode; switch ((IoControlCode & 0xFFFFFF0F)) { // The old deprecated ioctrl interface for backwards // compatibility. Do not use for new code. case IOCTL_GET_INFO_DEPRECATED: { char *buffer = ExAllocatePoolWithTag(NonPagedPoolNx, 0x1000, PMEM_POOL_TAG); if (buffer) { struct DeprecatedPmemMemoryInfo *info = (void *)IoBuffer; struct PmemMemoryInfo *memory_info = (void *)buffer; status = AddMemoryRanges(memory_info, 0x1000); if (status != STATUS_SUCCESS) { ExFreePoolWithTag(buffer, PMEM_POOL_TAG); goto exit; }; info->CR3.QuadPart = CR3.QuadPart; info->NumberOfRuns = (unsigned long)memory_info->NumberOfRuns.QuadPart; // Is there enough space in the user supplied buffer? if (OutputLen < (info->NumberOfRuns * sizeof(PHYSICAL_MEMORY_RANGE) + sizeof(struct DeprecatedPmemMemoryInfo))) { status = STATUS_INFO_LENGTH_MISMATCH; ExFreePoolWithTag(buffer, PMEM_POOL_TAG); goto exit; }; // Copy the runs over. RtlCopyMemory(&info->Run[0], &memory_info->Run[0], info->NumberOfRuns * sizeof(PHYSICAL_MEMORY_RANGE)); // This is the total length of the response. Irp->IoStatus.Information = sizeof(struct DeprecatedPmemMemoryInfo) + info->NumberOfRuns * sizeof(PHYSICAL_MEMORY_RANGE); WinDbgPrint("Returning info on the system memory using deprecated " "interface!\n"); ExFreePoolWithTag(buffer, PMEM_POOL_TAG); status = STATUS_SUCCESS; }; }; break; // Return information about memory layout etc through this ioctrl. case IOCTL_GET_INFO: { struct PmemMemoryInfo *info = (void *)IoBuffer; if (OutputLen < sizeof(struct PmemMemoryInfo)) { status = STATUS_INFO_LENGTH_MISMATCH; goto exit; }; // Ensure we clear the buffer first. RtlZeroMemory(IoBuffer, sizeof(struct PmemMemoryInfo)); // Get the memory ranges according to the mode. if (ext->mode == ACQUISITION_MODE_PTE_MMAP_WITH_PCI_PROBE) { status = PCI_AddMemoryRanges(info, OutputLen); } else { status = AddMemoryRanges(info, OutputLen); } if (status != STATUS_SUCCESS) { goto exit; }; WinDbgPrint("Returning info on the system memory.\n"); // We are currently running in user context which means __readcr3() will // return the process CR3. So we return the kernel CR3 we found // when loading. info->CR3.QuadPart = CR3.QuadPart; info->NtBuildNumber.QuadPart = *NtBuildNumber; info->NtBuildNumberAddr.QuadPart = (uintptr_t)NtBuildNumber; info->KernBase.QuadPart = (uintptr_t)KernelGetModuleBaseByPtr( NtBuildNumber, "NtBuildNumber"); // Fill in KPCR. GetKPCR(info); // This is the length of the response. Irp->IoStatus.Information = sizeof(struct PmemMemoryInfo) + info->NumberOfRuns.LowPart * sizeof(PHYSICAL_MEMORY_RANGE); status = STATUS_SUCCESS; }; break; case IOCTL_SET_MODE: { WinDbgPrint("Setting Acquisition mode.\n"); /* First u32 is the acquisition mode. */ if (InputLen >= sizeof(u32)) { enum PMEM_ACQUISITION_MODE mode = *(u32 *)IoBuffer; switch(mode) { case ACQUISITION_MODE_PHYSICAL_MEMORY: // These are all the requirements for this method. if (!Pmem_KernelExports.MmGetPhysicalMemoryRanges) { WinDbgPrint("Kernel APIs required for this method are not " "available."); status = STATUS_UNSUCCESSFUL; } else { WinDbgPrint("Using physical memory device for acquisition.\n"); status = STATUS_SUCCESS; ext->mode = mode; }; break; case ACQUISITION_MODE_MAP_IO_SPACE: if (!Pmem_KernelExports.MmGetPhysicalMemoryRanges || !Pmem_KernelExports.MmMapIoSpace || !Pmem_KernelExports.MmUnmapIoSpace) { WinDbgPrint("Kernel APIs required for this method are not " "available."); status = STATUS_UNSUCCESSFUL; } else { WinDbgPrint("Using MmMapIoSpace for acquisition.\n"); status = STATUS_SUCCESS; ext->mode = mode; }; break; case ACQUISITION_MODE_PTE_MMAP: if (!Pmem_KernelExports.MmGetVirtualForPhysical || !Pmem_KernelExports.MmGetPhysicalMemoryRanges || !ext->pte_mmapper) { WinDbgPrint("Kernel APIs required for this method are not " "available."); status = STATUS_UNSUCCESSFUL; } else { WinDbgPrint("Using PTE Remapping for acquisition.\n"); status = STATUS_SUCCESS; ext->mode = mode; }; break; case ACQUISITION_MODE_PTE_MMAP_WITH_PCI_PROBE: if (!Pmem_KernelExports.MmGetVirtualForPhysical || !ext->pte_mmapper) { WinDbgPrint("Kernel APIs required for this method are not " "available."); status = STATUS_UNSUCCESSFUL; } else { WinDbgPrint("Using PTE Remapping with PCI probe for acquisition.\n"); status = STATUS_SUCCESS; ext->mode = mode; }; break; default: WinDbgPrint("Invalid acquisition mode %d.\n", mode); status = STATUS_INVALID_PARAMETER; }; } else { status = STATUS_INFO_LENGTH_MISMATCH; }; }; break; #if PMEM_WRITE_ENABLED == 1 case IOCTL_WRITE_ENABLE: { ext->WriteEnabled = !ext->WriteEnabled; WinDbgPrint("Write mode is %d. Do you know what you are doing?\n", ext->WriteEnabled); status = STATUS_SUCCESS; }; break; #endif default: { WinDbgPrint("Invalid IOCTRL %d\n", IoControlCode); status = STATUS_INVALID_PARAMETER; }; } exit: Irp->IoStatus.Status = status; IoCompleteRequest(Irp,IO_NO_INCREMENT); return status; }
NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryString ) { NTSTATUS ntStatus = STATUS_SUCCESS; UNICODE_STRING uDeviceName, uDosDeviceName; unsigned int iCount = 0; PVOID pStackAttach = NULL; HANDLE hThreadHandle = NULL; OBJECT_ATTRIBUTES ObjectAttributes; SCOPE(__FUNCTION__); RtlInitUnicodeString( &uDeviceName, DeviceName ); RtlInitUnicodeString( &uDosDeviceName, DosDeviceName ); // We are assigned to the device of null.sys and create a new symbolic link //ntStatus = IoCreateSymbolicLink( &uDosDeviceName, &uDeviceName ); //if( !NT_SUCCESS(ntStatus) ) //{ // KdPrint(("Fail on IoCreateSymbolicLink. ntStatus: 0x%08x", ntStatus)); // return ntStatus; //} KdPrint(("Loading driver. pDriverObject 0x%08x\n pRegistryString %wZ\n Build at "__TIME__" "__DATE__"\n", pDriverObject, pRegistryString)); /* Only for testing purposes */ IoCreateDevice( pDriverObject, 0, &uDeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &g_Device ); IoCreateSymbolicLink( &uDosDeviceName, &uDeviceName ); // Set new major functions for( iCount = 0; iCount < IRP_MJ_MAXIMUM_FUNCTION; iCount++ ) pDriverObject->MajorFunction[iCount] = OnDispatch; pDriverObject->DriverUnload = DriverUnload; // Retrieve process offset in EPROCESS if( !GetProcessNameOffset() ) { KdPrint(("Error getting process name offset!\n")); ntStatus = STATUS_UNSUCCESSFUL; return ntStatus; } // Retrieve kernel base pointer pStackAttach = (PVOID)&KeStackAttachProcess; g_pKrnlBase = KernelGetModuleBaseByPtr( pStackAttach, "KeStackAttachProcess" ); if( !g_pKrnlBase ) { KdPrint(("Error getting ntoskrnl base!\n")); ntStatus = STATUS_UNSUCCESSFUL; return ntStatus; } KdPrint(("Kernel base: 0x%08x\n", g_pKrnlBase)); // Retrieve kernel name (differs from system to system) if( !GetModuleNameByBase( g_pKrnlBase, szKernelName, NULL ) ) { KdPrint(("Error getting kernel name by base\n")); ntStatus = STATUS_UNSUCCESSFUL; return ntStatus; } KdPrint(("NT OS Kernel Name: %s\n", szKernelName)); /* We ignore errors here. Cheat just won't work if something fails */ InitializeObjectAttributes( &ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL ); PsCreateSystemThread( &hThreadHandle, GENERIC_ALL, &ObjectAttributes, NULL, NULL, InitializeThread, NULL ); ZwClose( hThreadHandle ); DESCOPE(); return ntStatus; }