void GetGuestState() { PHYSICAL_ADDRESS HighestAcceptableAddress; HighestAcceptableAddress.QuadPart = 0xFFFFFFFF00000000; g_GuestState.CR0 = __readcr0(); g_GuestState.CR3 = __readcr3(); g_GuestState.CR4 = __readcr4() | CR4_VMXE; g_GuestState.RFLAGS = __readeflags(); g_GuestState.Cs = __readcs(); g_GuestState.Ds = __readds(); g_GuestState.Es = __reades(); g_GuestState.Ss = __readss(); g_GuestState.Fs = __readfs(); g_GuestState.Gs = __readgs(); g_GuestState.Ldtr = __sldt(); g_GuestState.Tr = __str(); __sgdt(&(g_GuestState.Gdtr)); __sidt(&(g_GuestState.Idtr)); g_GuestState.S_CS = __readmsr(IA32_SYSENTER_CS); g_GuestState.SEIP = __readmsr(IA64_SYSENTER_EIP); g_GuestState.SESP = __readmsr(IA32_SYSENTER_ESP); g_GuestState.VMXON = MmAllocateNonCachedMemory(PAGE_SIZE); RtlZeroMemory(g_GuestState.VMXON, PAGE_SIZE); g_GuestState.VMCS = MmAllocateNonCachedMemory(PAGE_SIZE); RtlZeroMemory(g_GuestState.VMCS, PAGE_SIZE); g_GuestState.hvStack = // 分配的是非页面内存, 且保证在物理内存中是连续的, MmFreeContiguousMemory MmAllocateContiguousMemory(PAGE_SIZE * 2, HighestAcceptableAddress); RtlZeroMemory(g_GuestState.hvStack, PAGE_SIZE * 2); }
static struct virtqueue * FindVirtualQueue(VirtIODevice *dev, ULONG index, USHORT vector) { struct virtqueue *pq = NULL; PVOID p; ULONG size, allocSize; VirtIODeviceQueryQueueAllocation(dev, index, &size, &allocSize); if (allocSize) { PHYSICAL_ADDRESS HighestAcceptable; HighestAcceptable.QuadPart = 0xFFFFFFFFFF; p = MmAllocateContiguousMemory(allocSize, HighestAcceptable); if (p) { pq = VirtIODevicePrepareQueue(dev, index, MmGetPhysicalAddress(p), p, allocSize, p, FALSE); if (vector != VIRTIO_MSI_NO_VECTOR) { WriteVirtIODeviceWord(dev->addr + VIRTIO_MSI_QUEUE_VECTOR, vector); vector = ReadVirtIODeviceWord(dev->addr + VIRTIO_MSI_QUEUE_VECTOR); } } } return pq; }
void vcpu_init(uintptr_t sp, uintptr_t ip, struct ksm *k) { struct vcpu *vcpu = ExAllocatePool(NonPagedPoolNx, sizeof(*vcpu)); if (!vcpu) return; RtlZeroMemory(vcpu, sizeof(*vcpu)); if (!ept_init(&vcpu->ept)) return ExFreePool(vcpu); PHYSICAL_ADDRESS highest; highest.QuadPart = -1; vcpu->stack = MmAllocateContiguousMemory(KERNEL_STACK_SIZE, highest); if (!vcpu->stack) goto out; RtlZeroMemory(vcpu->stack, KERNEL_STACK_SIZE); vcpu->vmcs = ExAllocatePool(NonPagedPoolNx, PAGE_SIZE); if (!vcpu->vmcs) goto out; RtlZeroMemory(vcpu->vmcs, PAGE_SIZE); vcpu->vmxon = ExAllocatePool(NonPagedPoolNx, PAGE_SIZE); if (!vcpu->vmxon) goto out; RtlZeroMemory(vcpu->vmxon, PAGE_SIZE); vcpu->ve = ExAllocatePool(NonPagedPoolNx, PAGE_SIZE); if (!vcpu->ve) goto out; RtlZeroMemory(vcpu->ve, PAGE_SIZE); vcpu->idt.limit = PAGE_SIZE - 1; vcpu->idt.base = (uintptr_t)ExAllocatePool(NonPagedPoolNx, PAGE_SIZE); if (!vcpu->idt.base) goto out; for (int i = 0; i < 0x100; ++i) vcpu->shadow_idt[i] = (struct kidt_entry64) { .e32 = (kidt_entry_t) { .p = 0 } }; vcpu->nr = cpu_nr(); k->vcpu_list[cpu_nr()] = vcpu; if (!enter_vmx(vcpu->vmxon)) goto out; if (!init_vmcs(vcpu->vmcs)) goto out_off; if (setup_vmcs(vcpu, sp, ip, (uintptr_t)vcpu->stack + KERNEL_STACK_SIZE)) vcpu_launch(); out_off: __vmx_off(); out: vcpu_free(vcpu); }
int dump_hook_init(PDRIVER_OBJECT drv_obj) { PLDR_DATA_TABLE_ENTRY table; PHYSICAL_ADDRESS high_addr; PLIST_ENTRY entry; NTSTATUS status; int resl = 0; ExInitializeFastMutex(&dump_sync); ExAcquireFastMutex(&dump_sync); /* find PsLoadedModuleListHead */ entry = ((PLIST_ENTRY)(drv_obj->DriverSection))->Flink; while (entry != drv_obj->DriverSection) { table = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); entry = entry->Flink; if ( (table->BaseDllName.Length == 0x18) && (p32(table->BaseDllName.Buffer)[0] == 0x0074006E) ) { ps_loaded_mod_list = pv(table->InLoadOrderLinks.Blink); break; } } ExReleaseFastMutex(&dump_sync); do { if (ps_loaded_mod_list == NULL) break; status = PsSetLoadImageNotifyRoutine(load_img_routine); if (NT_SUCCESS(status) == FALSE) break; high_addr.HighPart = 0; high_addr.LowPart = 0xFFFFFFFF; dump_mem = MmAllocateContiguousMemory(DUMP_MEM_SIZE, high_addr); if (dump_mem == NULL) break; dump_mdl = IoAllocateMdl(dump_mem, DUMP_MEM_SIZE, FALSE, FALSE, NULL); if (dump_mdl == NULL) break; MmBuildMdlForNonPagedPool(dump_mdl); memset(dump_mem, 0, DUMP_MEM_SIZE); resl = 1; } while (0); if (resl == 0) { if (dump_mdl != NULL) IoFreeMdl(dump_mdl); if (dump_mem != NULL) MmFreeContiguousMemory(dump_mem); } return resl; }
PSHV_GLOBAL_DATA ShvVpAllocateGlobalData ( VOID ) { PHYSICAL_ADDRESS lowest, highest; PSHV_GLOBAL_DATA data; ULONG cpuCount, size; // // The entire address range is OK for this allocation // lowest.QuadPart = 0; highest.QuadPart = lowest.QuadPart - 1; // // Query the number of logical processors, including those potentially in // groups other than 0. This allows us to support >64 processors. // cpuCount = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS); // // Each processor will receive its own slice of per-virtual processor data. // size = FIELD_OFFSET(SHV_GLOBAL_DATA, VpData) + cpuCount * sizeof(SHV_VP_DATA); // // Allocate a contiguous chunk of RAM to back this allocation and make sure // that it is RW only, instead of RWX, by using the new Windows 8 API. // #if TARGETVERSION > 7 data = (PSHV_GLOBAL_DATA)MmAllocateContiguousNodeMemory(size, lowest, highest, lowest, PAGE_READWRITE, MM_ANY_NODE_OK); #else data = (PSHV_GLOBAL_DATA)MmAllocateContiguousMemory(size, highest); #endif // TARGETVERSION > 7 if (data != NULL) { // // Zero out the entire data region // __stosq((PULONGLONG)data, 0, size / sizeof(ULONGLONG)); } // // Return what is hopefully a valid pointer, otherwise NULL. // return data; }
IDmaChannel* CDmaChannel::Create(ULONG size, PHYSICAL_ADDRESS highestAddress) { PVOID buffer = MmAllocateContiguousMemory(size, highestAddress); if(buffer != NULL) { return new CDmaChannel(buffer, size); } else { debug(DWDM,"CDmaChannel::Create: Allocating continguous memory failed\n"); return NULL; } }
static PVIOQUEUE FindVirtualQueue(VIODEVICE *dev, ULONG index) { PVIOQUEUE pq = NULL; PVOID p; ULONG size, allocSize; VirtIODeviceQueryQueueAllocation(dev, index, &size, &allocSize); if (allocSize) { PHYSICAL_ADDRESS HighestAcceptable; HighestAcceptable.QuadPart = 0xFFFFFFFFFF; p = MmAllocateContiguousMemory(allocSize, HighestAcceptable); if (p) { pq = VirtIODevicePrepareQueue(dev, index, MmGetPhysicalAddress(p), p, allocSize, p, FALSE); } } return pq; }
CVirtualizedCpu::CVirtualizedCpu( __in BYTE cpuCore, __in_opt const VMTrap traps[MAX_CALLBACK], __in_opt ULONG_PTR exceptionMask, __in_opt const VMCallback callback, __in_opt const VOID* param ) : m_vmx(PROCID(cpuCore), exceptionMask), m_cpuCore(cpuCore) { LARGE_INTEGER HighestAcceptableAddress; HighestAcceptableAddress.HighPart = -1; m_hvStack = reinterpret_cast<ULONG_PTR*>(MmAllocateContiguousMemory(HYPERVISOR_STACK_PAGE, HighestAcceptableAddress)); if (NULL == m_hvStack) return; RtlZeroMemory(m_hvStack, HYPERVISOR_STACK_PAGE); m_hvStack[0] = kStackMark; m_hvStack[1] = (ULONG_PTR)param; ::new(m_hvStack + 2) CHyperVisor(cpuCore, traps, callback); }
/** * Allocates physical contiguous memory (below 4GB). * The allocation is page aligned and its contents is undefined. * * @returns Pointer to the memory block. This is page aligned. * @param pPhys Where to store the physical address. * @param cb The allocation size in bytes. This is always * rounded up to PAGE_SIZE. */ RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb) { /* * validate input. */ Assert(VALID_PTR(pPhys)); Assert(cb > 0); /* * Allocate and get physical address. * Make sure the return is page aligned. */ PHYSICAL_ADDRESS MaxPhysAddr; MaxPhysAddr.HighPart = 0; MaxPhysAddr.LowPart = 0xffffffff; cb = RT_ALIGN_Z(cb, PAGE_SIZE); void *pv = MmAllocateContiguousMemory(cb, MaxPhysAddr); if (pv) { if (!((uintptr_t)pv & PAGE_OFFSET_MASK)) /* paranoia */ { PHYSICAL_ADDRESS PhysAddr = MmGetPhysicalAddress(pv); if (!PhysAddr.HighPart) /* paranoia */ { *pPhys = (RTCCPHYS)PhysAddr.LowPart; return pv; } /* failure */ AssertMsgFailed(("MMAllocContiguousMemory returned high address! PhysAddr=%RX64\n", (uint64_t)PhysAddr.QuadPart)); } else AssertMsgFailed(("MMAllocContiguousMemory didn't return a page aligned address - %p!\n", pv)); MmFreeContiguousMemory(pv); } return NULL; }
STDMETHODIMP_(NTSTATUS) CDmaChannel::AllocateBuffer(ULONG newBufferSize, PPHYSICAL_ADDRESS constraint OPTIONAL) { // free current buffer FreeBuffer(); // re-allocate buffer = MmAllocateContiguousMemory(newBufferSize,*constraint); if(buffer) { allocatedSize=newBufferSize; bufferSize=newBufferSize; physicalBufstart=MmGetPhysicalAddress(buffer); return STATUS_SUCCESS; } else { debug(DWDM,"!! CDmaChannel::AllocateBuffer: could not re-allocate buffer (%d->%d)\n",allocatedSize,bufferSize); allocatedSize=0; bufferSize=0; return STATUS_INSUFFICIENT_RESOURCES; } }
void XLaunchXBE(const char* fullpath) { char* xbename; char devicepath[MAX_PATH]; char launchpath[MAX_PATH]; char* lastslash; OutputDebugString(__FUNCTION__" - Path: "); OutputDebugString(fullpath); OutputDebugString("\n"); xbename = strrchr(fullpath, '\\'); if( xbename == NULL ) { OutputDebugString(__FUNCTION__" - Unable to find xbename\n"); return; } xbename++; if( fullpath[1] == ':' ) { char drive = toupper(fullpath[0]); int i; /* lookup partition path for given drive */ for(i = 0; i < NUM_OF_DRIVES; i++) { if( drive == g_driveMapping[i].szDriveLetter ) { strcpy(devicepath, "\\Device\\"); strcat(devicepath, g_driveMapping[i].szDevice); break; } } /* add the rest of the path */ strcat(devicepath, fullpath+2); } else strcpy(devicepath, fullpath); OutputDebugString(__FUNCTION__" - Device Path: "); OutputDebugString(devicepath); OutputDebugString("\n"); /* find the xbe name */ lastslash = strrchr(devicepath, '\\'); if( lastslash == NULL ) { OutputDebugString(__FUNCTION__" - Unable to find xbe name\n"); return; } /* get rid of xbe name from devicepath */ *lastslash = '\0'; /* mount this path to drive D: */ XUnmount("D:"); if( !XMount("D:", devicepath ) ) { OutputDebugString(__FUNCTION__" - Unable to mount drive\n"); return; } strcpy(launchpath, "D:\\"); strcat(launchpath, xbename); { /* check so file exists*/ struct stat buffer; if( stat(launchpath, &buffer) != 0 ) { OutputDebugString(__FUNCTION__" - File not found\n"); return; } } /* sometimes xdk doesn't allocate this area properly */ /* let's do it manually, and launch manually so we can keep any extra parameters given */ if ( (*LaunchDataPage) == NULL) { (*LaunchDataPage) = MmAllocateContiguousMemory(0x1000); MmPersistContiguousMemory((*LaunchDataPage), 0x1000, TRUE); memset((void*)(*LaunchDataPage), 0, 0x1000); /* set some launch info */ (*LaunchDataPage)->Header.dwLaunchDataType = LDT_FROM_DASHBOARD; (*LaunchDataPage)->Header.dwTitleId = 0; } /* these flags seem to tell the debug bios to return to debug dash */ /* reseting these for now, untill we know of anything needing to have that set*/ (*LaunchDataPage)->Header.dwFlags = 0; strcpy((*LaunchDataPage)->Header.szLaunchPath, devicepath); strcat((*LaunchDataPage)->Header.szLaunchPath, ";"); strcat((*LaunchDataPage)->Header.szLaunchPath, xbename); /* now tell bios to startup */ HalReturnToFirmware(ReturnFirmwareQuickReboot); /* crap function returned, something failed */ OutputDebugString(__FUNCTION__" - Failed"); }
NTSTATUS InitMyPCI(IN PDEVICE_EXTENSION pdx,IN PCM_PARTIAL_RESOURCE_LIST list) { PDEVICE_OBJECT fdo = pdx->fdo; ULONG vector; KIRQL irql; KINTERRUPT_MODE mode; KAFFINITY affinity; BOOLEAN irqshare; BOOLEAN gotinterrupt = FALSE; PHYSICAL_ADDRESS portbase; BOOLEAN gotport = FALSE; PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = &list->PartialDescriptors[0]; ULONG nres = list->Count; BOOLEAN IsMem0 = TRUE; for (ULONG i = 0; i < nres; ++i, ++resource) { // for each resource switch (resource->Type) { // switch on resource type case CmResourceTypePort: portbase = resource->u.Port.Start; pdx->nports = resource->u.Port.Length; pdx->mappedport = (resource->Flags & CM_RESOURCE_PORT_IO) == 0; gotport = TRUE; break; case CmResourceTypeMemory: if (IsMem0) { pdx->MemBar0 = (PUCHAR)MmMapIoSpace(resource->u.Memory.Start, resource->u.Memory.Length, MmNonCached); pdx->nMem0 = resource->u.Memory.Length; IsMem0 = FALSE; }else { pdx->MemBar1 = (PUCHAR)MmMapIoSpace(resource->u.Memory.Start, resource->u.Memory.Length, MmNonCached); pdx->nMem1 = resource->u.Memory.Length; } break; case CmResourceTypeInterrupt: irql = (KIRQL) resource->u.Interrupt.Level; vector = resource->u.Interrupt.Vector; affinity = resource->u.Interrupt.Affinity; mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive; irqshare = resource->ShareDisposition == CmResourceShareShared; gotinterrupt = TRUE; break; default: KdPrint(("Unexpected I/O resource type %d\n", resource->Type)); break; } // switch on resource type } // for each resource if (!(TRUE&& gotport&& gotinterrupt )) { KdPrint((" Didn't get expected I/O resources\n")); return STATUS_DEVICE_CONFIGURATION_ERROR; } if (pdx->mappedport) { // map port address for RISC platform pdx->portbase = (PUCHAR) MmMapIoSpace(portbase, pdx->nports, MmNonCached); if (!pdx->mappedport) { KdPrint(("Unable to map port range %I64X, length %X\n", portbase, pdx->nports)); return STATUS_INSUFFICIENT_RESOURCES; } } // map port address for RISC platform else pdx->portbase = (PUCHAR) portbase.QuadPart; NTSTATUS status = IoConnectInterrupt(&pdx->InterruptObject, (PKSERVICE_ROUTINE) OnInterrupt, (PVOID) pdx, NULL, vector, irql, irql, LevelSensitive, TRUE, affinity, FALSE); if (!NT_SUCCESS(status)) { KdPrint(("IoConnectInterrupt failed - %X\n", status)); if (pdx->portbase && pdx->mappedport) MmUnmapIoSpace(pdx->portbase, pdx->nports); pdx->portbase = NULL; return status; } #define IMAGE_LENGTH (640*480) //申请一段连续物理地址来读取图像 PHYSICAL_ADDRESS maxAddress; maxAddress.u.LowPart = 0xFFFFFFFF; maxAddress.u.HighPart = 0; pdx->MemForImage = MmAllocateContiguousMemory(IMAGE_LENGTH,maxAddress); PHYSICAL_ADDRESS pycialAddressForImage = MmGetPhysicalAddress(pdx->MemForImage); WRITE_REGISTER_BUFFER_UCHAR((PUCHAR)pdx->MemBar0+0x10000, (PUCHAR)&pycialAddressForImage.u.LowPart,4); return STATUS_SUCCESS; }
NTSTATUS DriverDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PIO_STACK_LOCATION IrpSp; ULONG IOControlCode = 0; ULONG dwBytesWritten = 0; PCHAR pInBuf = NULL, pOutBuf = NULL; unsigned int _cpu_thread_id = 0; unsigned int new_cpu_thread_id = 0; ULONG _num_active_cpus = 0; KAFFINITY _kaffinity = 0; UINT32 core_id = 0; // // Get the current IRP stack location of this request // IrpSp = IoGetCurrentIrpStackLocation (Irp); IOControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; DbgPrint( "[chipsec] >>>>>>>>>> IOCTL >>>>>>>>>>\n" ); DbgPrint( "[chipsec] DeviceObject = 0x%x IOCTL = 0x%x\n", DeviceObject, IOControlCode ); DbgPrint( "[chipsec] InputBufferLength = 0x%x, OutputBufferLength = 0x%x\n", IrpSp->Parameters.DeviceIoControl.InputBufferLength, IrpSp->Parameters.DeviceIoControl.OutputBufferLength ); // // CPU thread ID // _num_active_cpus = KeQueryActiveProcessorCount( NULL ); _kaffinity = KeQueryActiveProcessors(); _cpu_thread_id = KeGetCurrentProcessorNumber(); DbgPrint( "[chipsec] Active CPU threads : %d (KeNumberProcessors = %d)\n", _num_active_cpus, KeNumberProcessors ); DbgPrint( "[chipsec] Active CPU mask (KAFFINITY): 0x%08X\n", _kaffinity ); DbgPrint( "[chipsec] Current CPU thread : %d\n", _cpu_thread_id ); // // Switch on the IOCTL code that is being requested by the user. If the // operation is a valid one for this device do the needful. // Irp -> IoStatus.Information = 0; switch( IOControlCode ) { case READ_PCI_CFG_REGISTER: { DWORD val; BYTE size = 0; WORD bdf[4]; BYTE bus = 0, dev = 0, fun = 0, off = 0; DbgPrint( "[chipsec] > READ_PCI_CFG_REGISTER\n" ); RtlCopyBytes( bdf,Irp->AssociatedIrp.SystemBuffer, 4*sizeof(WORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 4*sizeof(WORD), sizeof(BYTE) ); bus = (UINT8)bdf[0]; dev = (UINT8)bdf[1]; fun = (UINT8)bdf[2]; off = (UINT8)bdf[3]; if( 1 != size && 2 != size && 4 != size) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } val = ReadPCICfg( bus, dev, fun, off, size ); IrpSp->Parameters.Read.Length = size; RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&val, size ); DbgPrint( "[chipsec][READ_PCI_CFG_REGISTER] B/D/F: %#04x/%#04x/%#04x, OFFSET: %#04x, value = %#010x (size = 0x%x)\n", bus, dev, fun, off, val, size ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case WRITE_PCI_CFG_REGISTER: { DWORD val = 0; WORD bdf[6]; BYTE bus = 0, dev = 0, fun = 0, off = 0; BYTE size = 0; DbgPrint( "[chipsec] > WRITE_PCI_CFG_REGISTER\n" ); RtlCopyBytes( bdf, Irp->AssociatedIrp.SystemBuffer, 6 * sizeof(WORD) ); bus = (UINT8)bdf[0]; dev = (UINT8)bdf[1]; fun = (UINT8)bdf[2]; off = (UINT8)bdf[3]; RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 6*sizeof(WORD), sizeof(BYTE) ); val = ((DWORD)bdf[5] << 16) | bdf[4]; DbgPrint( "[chipsec][WRITE_PCI_CFG_REGISTER] B/D/F: %#02x/%#02x/%#02x, OFFSET: %#02x, value = %#010x (size = %#02x)\n", bus, dev, fun, off, val, size ); WritePCICfg( bus, dev, fun, off, size, val ); Status = STATUS_SUCCESS; break; } case IOCTL_READ_PHYSMEM: { UINT32 len = 0; PVOID virt_addr; PHYSICAL_ADDRESS phys_addr = { 0x0, 0x0 }; DbgPrint( "[chipsec] > IOCTL_READ_PHYSMEM\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength < 3*sizeof(UINT32)) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; phys_addr.HighPart = ((UINT32*)pInBuf)[0]; phys_addr.LowPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; if( !len ) len = 4; if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < len ) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } __try { Status = _read_phys_mem( phys_addr, len, pOutBuf ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] ERROR: exception code 0x%X\n", Status ); break; } if( NT_SUCCESS(Status) ) { DbgPrint( "[chipsec][IOCTL_READ_PHYSMEM] Contents:\n" ); _dump_buffer( (unsigned char *)pOutBuf, min(len,0x100) ); dwBytesWritten = len; } break; } case IOCTL_WRITE_PHYSMEM: { UINT32 len = 0; PVOID virt_addr = 0; PHYSICAL_ADDRESS phys_addr = { 0x0, 0x0 }; DbgPrint( "[chipsec] > IOCTL_WRITE_PHYSMEM\n" ); if( Irp->AssociatedIrp.SystemBuffer ) { pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } phys_addr.HighPart = ((UINT32*)pInBuf)[0]; phys_addr.LowPart = ((UINT32*)pInBuf)[1]; len = ((UINT32*)pInBuf)[2]; ((UINT32*)pInBuf) += 3; if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < len + 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] Writing contents:\n" ); _dump_buffer( (unsigned char *)pInBuf, min(len,0x100) ); __try { Status = _write_phys_mem( phys_addr, len, pInBuf ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_WRITE_PHYSMEM] ERROR: exception code 0x%X\n", Status ); break; } break; } } case IOCTL_ALLOC_PHYSMEM: { SIZE_T NumberOfBytes = 0; PVOID va = 0; PHYSICAL_ADDRESS HighestAcceptableAddress = { 0xFFFFFFFF, 0xFFFFFFFF }; DbgPrint( "[chipsec] > IOCTL_ALLOC_PHYSMEM\n" ); pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UINT64) + sizeof(UINT32)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &HighestAcceptableAddress.QuadPart, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); RtlCopyBytes( &NumberOfBytes, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(UINT64), sizeof(UINT32) ); DbgPrint( "[chipsec] Allocating: NumberOfBytes = 0x%X, PhysAddr = 0x%I64x", NumberOfBytes, HighestAcceptableAddress.QuadPart ); va = MmAllocateContiguousMemory( NumberOfBytes, HighestAcceptableAddress ); if( !va ) { DbgPrint( "[chipsec] ERROR: STATUS_UNSUCCESSFUL - could not allocate memory\n" ); Status = STATUS_UNSUCCESSFUL; } else if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < 2*sizeof(UINT64) ) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL - should be at least 2*UINT64\n" ); Status = STATUS_BUFFER_TOO_SMALL; } else { PHYSICAL_ADDRESS pa = MmGetPhysicalAddress( va ); DbgPrint( "[chipsec] Allocated Buffer: VirtAddr = 0x%I64x, PhysAddr = 0x%I64x\n", (UINT64)va, pa.QuadPart ); ((UINT64*)pOutBuf)[0] = (UINT64)va; ((UINT64*)pOutBuf)[1] = pa.QuadPart; IrpSp->Parameters.Read.Length = 2*sizeof(UINT64); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; } break; } case IOCTL_FREE_PHYSMEM: { UINT64 va = 0x0; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_FREE_PHYSMEM\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &va, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); DbgPrint( "[chipsec][IOCTL_FREE_PHYSMEM] Virtual address of the memory being freed: 0x%I64X\n", va ); MmFreeContiguousMemory( (PVOID)va ); IrpSp->Parameters.Read.Length = 0; dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_GET_PHYSADDR: { UINT64 va = 0x0; PHYSICAL_ADDRESS pa = { 0x0, 0x0 }; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_GET_PHYSADDR\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( &va, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT64) ); pa = MmGetPhysicalAddress( (PVOID)va ); DbgPrint( "[chipsec][IOCTL_GET_PHYSADDR] Traslated virtual address 0x%I64X to physical: 0x%I64X\n", va, pa.QuadPart, pa.LowPart); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&pa, sizeof(UINT64) ); IrpSp->Parameters.Read.Length = sizeof(UINT64); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_MAP_IO_SPACE: { PVOID va = 0x0; PHYSICAL_ADDRESS pa = { 0x0, 0x0 }; unsigned int len = 0; unsigned int cache_type = 0; pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; DbgPrint( "[chipsec] > IOCTL_MAP_IO_SPACE\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != 3*8) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT64)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( &pa, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x00, 0x8 ); RtlCopyBytes( &len, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x08, 0x4 ); RtlCopyBytes( &cache_type, (BYTE*)Irp->AssociatedIrp.SystemBuffer + 0x10, 0x4 ); va = MmMapIoSpace(pa, len, cache_type); DbgPrint( "[chipsec][IOCTL_MAP_IO_SPACE] Mapping physical address 0x%016llX to virtual 0x%016llX\n", pa, va); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&va, sizeof(va) ); IrpSp->Parameters.Read.Length = sizeof(va); dwBytesWritten = sizeof(va); Status = STATUS_SUCCESS; break; } case IOCTL_LOAD_UCODE_PATCH: { PVOID ucode_buf = NULL; UINT64 ucode_start = 0; UINT16 ucode_size = 0; UINT32 _eax = 0, _edx = 0; int CPUInfo[4] = {-1}; DbgPrint("[chipsec] > IOCTL_LOAD_UCODE_UPDATE\n" ); if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + sizeof(UINT16) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < 3)\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( &ucode_size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(UINT16) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Ucode update size = 0x%X\n", ucode_size ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < ucode_size + sizeof(BYTE) + sizeof(UINT16) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < ucode_size + 3)\n" ); Status = STATUS_INVALID_PARAMETER; break; } ucode_buf = ExAllocatePoolWithTag( NonPagedPool, ucode_size, 0x3184 ); if( !ucode_buf ) { DbgPrint( "[chipsec] ERROR: couldn't allocate pool for ucode binary\n" ); break; } RtlCopyBytes( ucode_buf, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE) + sizeof(UINT16), ucode_size ); ucode_start = (UINT64)ucode_buf; DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] ucode update address = 0x%p (eax = 0x%08X, edx = 0x%08X)\n", ucode_start, (UINT32)(ucode_start & 0xFFFFFFFF), (UINT32)((ucode_start >> 32) & 0xFFFFFFFF) ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] ucode update contents:\n" ); _dump_buffer( (unsigned char *)ucode_buf, min(ucode_size,0x100) ); // -- // -- trigger CPU ucode patch update // -- pInBuf points to the beginning of ucode update binary // -- _wrmsr( MSR_IA32_BIOS_UPDT_TRIG, (UINT32)((ucode_start >> 32) & 0xFFFFFFFF), (UINT32)(ucode_start & 0xFFFFFFFF) ); ExFreePoolWithTag( ucode_buf, 0x3184 ); // -- // -- check if patch was loaded // -- // -- need to clear IA32_BIOS_SIGN_ID MSR first // -- CPUID will deposit an update ID value in 64-bit MSR at address MSR_IA32_BIOS_SIGN_ID // -- read IA32_BIOS_SIGN_ID MSR to check patch ID != 0 // -- DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] checking ucode update was loaded..\n" ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] clear IA32_BIOS_SIGN_ID, CPUID EAX=1, read back IA32_BIOS_SIGN_ID\n" ); _wrmsr( MSR_IA32_BIOS_SIGN_ID, 0, 0 ); __cpuid(CPUInfo, 1); _rdmsr( MSR_IA32_BIOS_SIGN_ID, &_eax, &_edx ); DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] RDMSR( IA32_BIOS_SIGN_ID=0x8b ) = 0x%08x%08x\n", _edx, _eax ); if( 0 != _edx ) DbgPrint( "[chipsec][IOCTL_LOAD_UCODE_UPDATE] Microcode update loaded (ID != 0)\n" ); else DbgPrint( "[chipsec] ERROR: Microcode update failed\n" ); Status = STATUS_SUCCESS; break; } case IOCTL_WRMSR: { UINT32 msrData[3]; UINT32 _eax = 0, _edx = 0; unsigned int _msr_addr; DbgPrint("[chipsec] > IOCTL_WRMSR\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + 3*sizeof(UINT32) ) { DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: STATUS_INVALID_PARAMETER (input buffer size < sizeof(BYTE) + 3*sizeof(UINT32))\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_WRMSR] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( msrData, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), 3 * sizeof(UINT32) ); _msr_addr = msrData[0]; _eax = msrData[1]; _edx = msrData[2]; DbgPrint( "[chipsec][IOCTL_WRMSR] WRMSR( 0x%x ) <-- 0x%08x%08x\n", _msr_addr, _edx, _eax ); // -- // -- write MSR // -- __try { _wrmsr( _msr_addr, _edx, _eax ); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_WRMSR] ERROR: exception code 0x%X\n", Status ); break; } // -- // -- read MSR to check if it was written // -- // _rdmsr( _msr_addr, &_eax, &_edx ); // DbgPrint( "[chipsec][IOCTL_WRMSR] RDMSR( 0x%x ) --> 0x%08x%08x\n", _msr_addr, _edx, _eax ); Status = STATUS_SUCCESS; break; } case IOCTL_RDMSR: { UINT32 msrData[1]; UINT32 _eax = 0; UINT32 _edx = 0; UINT32 _msr_addr = 0; DbgPrint("[chipsec] > IOCTL_RDMSR\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; pOutBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: No input provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BYTE) + sizeof(UINT32) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER - input buffer size < sizeof(BYTE) + sizeof(UINT32)\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][IOCTL_RDMSR] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( msrData, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(UINT32) ); _msr_addr = msrData[0]; __try { _rdmsr( _msr_addr, &_eax, &_edx ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_RDMSR] ERROR: exception code 0x%X\n", Status ); break; } DbgPrint( "[chipsec][IOCTL_RDMSR] RDMSR( 0x%x ) --> 0x%08x%08x\n", _msr_addr, _edx, _eax ); if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= 2*sizeof(UINT32) ) { IrpSp->Parameters.Read.Length = 2*sizeof(UINT32); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&_eax, sizeof(UINT32) ); RtlCopyBytes( ((UINT8*)Irp->AssociatedIrp.SystemBuffer) + sizeof(UINT32), (VOID*)&_edx, sizeof(UINT32) ); dwBytesWritten = 2*sizeof(UINT32); Status = STATUS_SUCCESS; } else { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL - should be at least 2 UINT32\n" ); Status = STATUS_BUFFER_TOO_SMALL; } break; } case READ_IO_PORT: { DWORD value; BYTE size = 0; WORD io_port; DbgPrint( "[chipsec] > READ_IO_PORT\n" ); RtlCopyBytes( &io_port, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(WORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD), sizeof(BYTE) ); if( 1 != size && 2 != size && 4 != size) { DbgPrint( "[chipsec][READ_IO_PORT] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } __try { value = ReadIOPort( io_port, size ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][READ_IO_PORT] ERROR: exception code 0x%X\n", Status ); break; } IrpSp->Parameters.Read.Length = size; RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (VOID*)&value, size ); DbgPrint( "[chipsec][READ_IO_PORT] I/O Port %#04x, value = %#010x (size = %#02x)\n", io_port, value, size ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case WRITE_IO_PORT: { DWORD value = 0; WORD io_port = 0; BYTE size = 0; DbgPrint( "[chipsec] > WRITE_IO_PORT\n" ); RtlCopyBytes( &io_port, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(WORD) ); RtlCopyBytes( &value, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD), sizeof(DWORD) ); RtlCopyBytes( &size, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(WORD) + sizeof(DWORD), sizeof(BYTE) ); DbgPrint( "[chipsec][WRITE_IO_PORT] I/O Port %#04x, value = %#010x (size = %#02x)\n", io_port, value, size ); __try { WriteIOPort( value, io_port, size ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][WRITE_IO_PORT] ERROR: exception code 0x%X\n", Status ); break; } Status = STATUS_SUCCESS; break; } case GET_CPU_DESCRIPTOR_TABLE: { BYTE dt_code = 0; DESCRIPTOR_TABLE_RECORD dtr; PDESCRIPTOR_TABLE_RECORD pdtr = &dtr; PHYSICAL_ADDRESS dt_pa; DbgPrint( "[chipsec] > GET_CPU_DESCRIPTOR_TABLE\n" ); RtlCopyBytes( &new_cpu_thread_id, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(BYTE) ); if( new_cpu_thread_id >= _num_active_cpus ) new_cpu_thread_id = 0; KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Changed CPU thread to %d\n", KeGetCurrentProcessorNumber() ); RtlCopyBytes( &dt_code, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(BYTE), sizeof(BYTE) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table: %x\n", dt_code ); switch( dt_code ) { case CPU_DT_CODE_GDTR: { _store_gdtr( (void*)pdtr ); break; } case CPU_DT_CODE_LDTR: { _store_ldtr( (void*)pdtr ); break; } case CPU_DT_CODE_IDTR: default: { _store_idtr( (void*)pdtr ); break; } } DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table register contents:\n" ); _dump_buffer( (unsigned char *)pdtr, sizeof(DESCRIPTOR_TABLE_RECORD) ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] IDTR: Limit = 0x%04x, Base = 0x%I64x\n", dtr.limit, dtr.base ); dt_pa = MmGetPhysicalAddress( (PVOID)dtr.base ); DbgPrint( "[chipsec][GET_CPU_DESCRIPTOR_TABLE] Descriptor table PA: 0x%I64X (0x%08X_%08X)\n", dt_pa.QuadPart, dt_pa.HighPart, dt_pa.LowPart ); IrpSp->Parameters.Read.Length = sizeof(DESCRIPTOR_TABLE_RECORD) + sizeof(dt_pa.QuadPart); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)pdtr, sizeof(DESCRIPTOR_TABLE_RECORD) ); RtlCopyBytes( (UINT8*)Irp->AssociatedIrp.SystemBuffer + sizeof(DESCRIPTOR_TABLE_RECORD), (VOID*)&dt_pa.QuadPart, sizeof(dt_pa.QuadPart) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_SWSMI: { CPU_REG_TYPE gprs[6] = {0}; CPU_REG_TYPE _rax = 0, _rbx = 0, _rcx = 0, _rdx = 0, _rsi = 0, _rdi = 0; unsigned int _smi_code_data = 0; DbgPrint("[chipsec] > IOCTL_SWSMI\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UINT16) + sizeof(gprs) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < sizeof(UINT16) + sizeof(gprs))\n" ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &_smi_code_data, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(UINT16) ); RtlCopyBytes( gprs, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(UINT16), sizeof(gprs) ); _rax = gprs[ 0 ]; _rbx = gprs[ 1 ]; _rcx = gprs[ 2 ]; _rdx = gprs[ 3 ]; _rsi = gprs[ 4 ]; _rdi = gprs[ 5 ]; DbgPrint( "[chipsec][IOCTL_SWSMI] SW SMI to ports 0x%X-0x%X <- 0x%04X\n", 0xB2, 0xB3, _smi_code_data ); DbgPrint( " RAX = 0x%I64x\n", _rax ); DbgPrint( " RBX = 0x%I64x\n", _rbx ); DbgPrint( " RCX = 0x%I64x\n", _rcx ); DbgPrint( " RDX = 0x%I64x\n", _rdx ); DbgPrint( " RSI = 0x%I64x\n", _rsi ); DbgPrint( " RDI = 0x%I64x\n", _rdi ); // -- // -- send SMI using port 0xB2 // -- __try { _swsmi( _smi_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi ); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); break; } Status = STATUS_SUCCESS; break; } case IOCTL_CPUID: { DWORD CPUInfo[4] = {-1}; DWORD gprs[2] = {0}; DWORD _rax = 0, _rcx = 0; //CPU_REG_TYPE gprs[6]; //CPU_REG_TYPE _rax = 0, _rbx = 0, _rcx = 0, _rdx = 0, _rsi = 0, _rdi = 0; DbgPrint("[chipsec] > IOCTL_CPUID\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !pInBuf ) { DbgPrint( "[chipsec] ERROR: NO data provided\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(gprs) ) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER (input buffer size < %d)\n", sizeof(gprs) ); Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( gprs, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(gprs) ); _rax = gprs[ 0 ]; _rcx = gprs[ 1 ]; DbgPrint( "[chipsec][IOCTL_CPUID] CPUID:\n" ); DbgPrint( " EAX = 0x%08X\n", _rax ); DbgPrint( " ECX = 0x%08X\n", _rcx ); __cpuidex( CPUInfo, _rax, _rcx ); DbgPrint( "[chipsec][IOCTL_CPUID] CPUID returned:\n" ); DbgPrint( " EAX = 0x%08X\n", CPUInfo[0] ); DbgPrint( " EBX = 0x%08X\n", CPUInfo[1] ); DbgPrint( " ECX = 0x%08X\n", CPUInfo[2] ); DbgPrint( " EDX = 0x%08X\n", CPUInfo[3] ); IrpSp->Parameters.Read.Length = sizeof(CPUInfo); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)CPUInfo, sizeof(CPUInfo) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } case IOCTL_WRCR: { UINT64 val64 = 0; CPU_REG_TYPE value = 0; WORD cr_reg = 0; DbgPrint( "[chipsec] > WRITE_CR\n" ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (sizeof(cr_reg) + sizeof(val64) + sizeof(BYTE))) { Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &cr_reg, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(cr_reg) ); RtlCopyBytes( &val64, (BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg), sizeof(val64) ); new_cpu_thread_id = *((BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg) + sizeof(val64)); if( new_cpu_thread_id >= _num_active_cpus ) { // new_cpu_thread_id = 0; Status = STATUS_INVALID_PARAMETER; break; } KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); value = (CPU_REG_TYPE)val64; DbgPrint( "[chipsec][WRITE_CR] CR Reg %#04x, value = %#010x \n", cr_reg, value ); switch (cr_reg) { case 0: WriteCR0(value); Status = STATUS_SUCCESS; break; case 2: WriteCR2(value); Status = STATUS_SUCCESS; break; case 3: WriteCR3(value); Status = STATUS_SUCCESS; break; case 4: WriteCR4(value); Status = STATUS_SUCCESS; break; case 8: #if defined(_M_AMD64) WriteCR8(value); Status = STATUS_SUCCESS; break; #endif default: Status = STATUS_INVALID_PARAMETER; break; } if( !NT_SUCCESS(Status) ) { break; } dwBytesWritten = 0; Status = STATUS_SUCCESS; break; } case IOCTL_RDCR: { UINT64 val64 = 0; CPU_REG_TYPE value = 0; WORD cr_reg = 0; DbgPrint( "[chipsec] > READ_CR\n" ); if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (sizeof(cr_reg)+sizeof(BYTE)) || IrpSp->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(val64)) ) { Status = STATUS_INVALID_PARAMETER; break; } RtlCopyBytes( &cr_reg, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(cr_reg) ); new_cpu_thread_id = *((BYTE*)Irp->AssociatedIrp.SystemBuffer + sizeof(cr_reg)); if( new_cpu_thread_id >= _num_active_cpus ) { // new_cpu_thread_id = 0; Status = STATUS_INVALID_PARAMETER; break; } KeSetSystemAffinityThread( (KAFFINITY)(1 << new_cpu_thread_id) ); switch (cr_reg) { case 0: value = ReadCR0(); Status = STATUS_SUCCESS; break; case 2: value = ReadCR2(); Status = STATUS_SUCCESS; break; case 3: value = ReadCR3(); Status = STATUS_SUCCESS; break; case 4: value = ReadCR4(); Status = STATUS_SUCCESS; break; case 8: #if defined(_M_AMD64) value = ReadCR8(); Status = STATUS_SUCCESS; break; #endif default: Status = STATUS_INVALID_PARAMETER; break; } if( !NT_SUCCESS(Status) ) { break; } val64 = value; RtlCopyBytes( (BYTE*)Irp->AssociatedIrp.SystemBuffer, &val64, sizeof(val64) ); dwBytesWritten = sizeof(val64); DbgPrint( "[chipsec][READ_CR] CR Reg %#04x, value = %#010x \n", cr_reg, value ); Status = STATUS_SUCCESS; break; } case IOCTL_HYPERCALL: { CPU_REG_TYPE regs[11] = {0}; CPU_REG_TYPE result = 0; DbgPrint("[chipsec] > IOCTL_HYPERCALL\n"); pInBuf = Irp->AssociatedIrp.SystemBuffer; if( !Irp->AssociatedIrp.SystemBuffer || IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(regs)) { DbgPrint( "[chipsec] ERROR: STATUS_INVALID_PARAMETER\n" ); Status = STATUS_INVALID_PARAMETER; break; } if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(result)) { DbgPrint( "[chipsec] ERROR: STATUS_BUFFER_TOO_SMALL\n" ); Status = STATUS_BUFFER_TOO_SMALL; break; } RtlCopyBytes( regs, (BYTE*)Irp->AssociatedIrp.SystemBuffer, sizeof(regs) ); DbgPrint( "[chipsec][IOCTL_HYPERCALL] HYPERCALL:\n" ); #if defined(_M_AMD64) DbgPrint( " RCX = 0x%016llX RDX = 0x%016llX\n", regs[0], regs[1] ); DbgPrint( " R8 = 0x%016llX R9 = 0x%016llX\n", regs[2], regs[3] ); DbgPrint( " R10 = 0x%016llX R11 = 0x%016llX\n", regs[4], regs[5] ); DbgPrint( " RAX = 0x%016llX RBX = 0x%016llX\n", regs[6], regs[7] ); DbgPrint( " RDI = 0x%016llX RSI = 0x%016llX\n", regs[8], regs[9] ); #endif #if defined(_M_IX86) DbgPrint( " EAX = 0x%08X EBX = 0x%08X ECX = 0x%08X\n", regs[6], regs[7], regs[0] ); DbgPrint( " EDX = 0x%08X ESI = 0x%08X EDI = 0x%08X\n", regs[1], regs[8], regs[9] ); #endif DbgPrint( " XMM0-XMM5 buffer VA = 0x%016llX\n", regs[9] ); __try { result = hypercall(regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7], regs[8], regs[9], regs[10], &hypercall_page); } __except( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); DbgPrint( "[chipsec][IOCTL_HYPERCALL] ERROR: exception code 0x%X\n", Status ); break; } DbgPrint( "[chipsec][IOCTL_HYPERCALL] returned: 0x%016llX\n", result); IrpSp->Parameters.Read.Length = sizeof(result); RtlCopyBytes( Irp->AssociatedIrp.SystemBuffer, (void*)&result, sizeof(result) ); dwBytesWritten = IrpSp->Parameters.Read.Length; Status = STATUS_SUCCESS; break; } default: DbgPrint( "[chipsec] ERROR: invalid IOCTL\n"); Status = STATUS_NOT_IMPLEMENTED; break; } // -- switch
NTSTATUS DumpFilterEntry (PFILTER_EXTENSION filterExtension, PFILTER_INITIALIZATION_DATA filterInitData) { GetSystemDriveDumpConfigRequest dumpConfig; PHYSICAL_ADDRESS highestAcceptableWriteBufferAddr; STORAGE_DEVICE_NUMBER storageDeviceNumber; PARTITION_INFORMATION partitionInfo; LONG version; NTSTATUS status; Dump ("DumpFilterEntry type=%d\n", filterExtension->DumpType); filterInitData->MajorVersion = DUMP_FILTER_MAJOR_VERSION; filterInitData->MinorVersion = DUMP_FILTER_MINOR_VERSION; filterInitData->Flags |= DUMP_FILTER_CRITICAL; // Check driver version of the main device status = TCDeviceIoControl (NT_ROOT_PREFIX, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &version, sizeof (version)); if (!NT_SUCCESS (status)) goto err; if (version != VERSION_NUM) { status = STATUS_INVALID_PARAMETER; goto err; } // Get dump configuration from the main device status = TCDeviceIoControl (NT_ROOT_PREFIX, TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG, NULL, 0, &dumpConfig, sizeof (dumpConfig)); if (!NT_SUCCESS (status)) goto err; BootDriveFilterExtension = dumpConfig.BootDriveFilterExtension; if (BootDriveFilterExtension->MagicNumber != TC_BOOT_DRIVE_FILTER_EXTENSION_MAGIC_NUMBER) { status = STATUS_CRC_ERROR; goto err; } // KeSaveFloatingPointState() may generate a bug check during crash dump #if !defined (_WIN64) if (filterExtension->DumpType == DumpTypeCrashdump) dumpConfig.HwEncryptionEnabled = FALSE; #endif EnableHwEncryption (dumpConfig.HwEncryptionEnabled); if (!AutoTestAlgorithms()) { status = STATUS_INVALID_PARAMETER; goto err; } // Check dump volume is located on the system drive status = SendDeviceIoControlRequest (filterExtension->DeviceObject, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &storageDeviceNumber, sizeof (storageDeviceNumber)); if (!NT_SUCCESS (status)) goto err; if (!BootDriveFilterExtension->SystemStorageDeviceNumberValid) { status = STATUS_INVALID_PARAMETER; goto err; } if (storageDeviceNumber.DeviceNumber != BootDriveFilterExtension->SystemStorageDeviceNumber) { status = STATUS_ACCESS_DENIED; goto err; } // Check dump volume is located within the scope of system encryption status = SendDeviceIoControlRequest (filterExtension->DeviceObject, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &partitionInfo, sizeof (partitionInfo)); if (!NT_SUCCESS (status)) goto err; DumpPartitionOffset = partitionInfo.StartingOffset; if (DumpPartitionOffset.QuadPart < BootDriveFilterExtension->ConfiguredEncryptedAreaStart || DumpPartitionOffset.QuadPart > BootDriveFilterExtension->ConfiguredEncryptedAreaEnd) { status = STATUS_ACCESS_DENIED; goto err; } // Allocate buffer for encryption if (filterInitData->MaxPagesPerWrite == 0) { status = STATUS_INVALID_PARAMETER; goto err; } WriteFilterBufferSize = filterInitData->MaxPagesPerWrite * PAGE_SIZE; #ifdef _WIN64 highestAcceptableWriteBufferAddr.QuadPart = 0x7FFffffFFFFLL; #else highestAcceptableWriteBufferAddr.QuadPart = 0xffffFFFFLL; #endif WriteFilterBuffer = MmAllocateContiguousMemory (WriteFilterBufferSize, highestAcceptableWriteBufferAddr); if (!WriteFilterBuffer) { status = STATUS_INSUFFICIENT_RESOURCES; goto err; } filterInitData->DumpStart = DumpFilterStart; filterInitData->DumpWrite = DumpFilterWrite; filterInitData->DumpFinish = DumpFilterFinish; filterInitData->DumpUnload = DumpFilterUnload; Dump ("Dump filter loaded type=%d\n", filterExtension->DumpType); return STATUS_SUCCESS; err: Dump ("DumpFilterEntry error %x\n", status); return status; }
// This runs at a lower IRQL, so it can use the kernel memory functions void processCreationMonitor(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create) { PEPROCESS proc = NULL; void *PeHeaderVirt = NULL; uint16 numExecSections = 0; uint8 *pePtr = NULL; PHYSICAL_ADDRESS phys = {0}; char *procName; uint32 imageSize, translations = (uint32) translationArr; NTSTATUS status = STATUS_SUCCESS; HANDLE periodMeasureThreadHandle = NULL; OBJECT_ATTRIBUTES objectAttributes = {0}; // Set to anywhere inthe 4GB range highestMemoryAddress.LowPart = ~0; // Get the 8.3 image name PsLookupProcessByProcessId(ProcessId, &proc); procName = PsGetProcessImageFileName(proc); // Check if this is the target process if(strncmp(TargetAppName, procName, strlen(TargetAppName)) == 0) { if (Create && VDEBUG) DbgPrint("New Process Created! %s\r\n", procName); if (!Create && VDEBUG) DbgPrint("Application quitting %s\r\n", procName); // Retrieve virtual pointer to the PE header for target application (in PE context) PeHeaderVirt = PsGetProcessSectionBaseAddress(proc); //DbgPrint("Virt: %x", PeHeaderVirt); // Begin critical section // Attach to the target process and grab its CR3 value to use later KeStackAttachProcess(proc, &apcstate); if (Create) { __asm { push eax mov eax, cr3 mov targetCR3, eax pop eax } } phys = MmGetPhysicalAddress(PeHeaderVirt); KeUnstackDetachProcess(&apcstate); // End critical section targetPePhys = phys; targetPeVirt = PeHeaderVirt; targetProc = proc; if (Create) { targetPePtr = peMapInImageHeader(phys); imageSize = peGetImageSize(targetPePtr); if (VDEBUG) DbgPrint("Image Size: %x bytes Num Entries %d\r\n", imageSize, sizeof(TlbTranslation) * (imageSize / PAGE_SIZE)); DbgPrint("Virt %x - %x %x\r\n", PeHeaderVirt, (uint32) PeHeaderVirt + imageSize, targetCR3); // Ensure Windows doesn't reuse the physical pages LockedMdl = pagingLockProcessMemory(PeHeaderVirt, imageSize, proc, &apcstate); if(LockedMdl == NULL && VDEBUG) { DbgPrint("Unable to lock memory\r\n"); } appsize = imageSize; appCopy = (uint8 *) MmAllocateContiguousMemory(imageSize, highestMemoryAddress); RtlZeroMemory((void *) appCopy, imageSize); copyPe(proc, &apcstate, PeHeaderVirt, appCopy, imageSize); translationArr = allocateAndFillTranslationArray(PeHeaderVirt, appCopy, imageSize, proc, &apcstate); translations = (uint32) translationArr; // VMCALL to start the TLB splitting __asm { PUSHAD MOV EAX, VMCALL_INIT_SPLIT MOV EBX, translations _emit 0x0F // VMCALL _emit 0x01 _emit 0xC1 POPAD } if (VDEBUG) DbgPrint("Checksum of proc: %x\r\n", peChecksumExecSections(targetPePtr, PeHeaderVirt, proc, &apcstate, targetPhys)); //pePrintSections(pePtr); #ifdef PERIODIC_MEASURE /* Set up periodic measurement thread */ KeInitializeEvent(&periodicMeasureThreadWakeUp, NotificationEvent, FALSE); //returns void InitializeObjectAttributes(&objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); //returns void periodicMeasureThreadExecute = 1; //allows thread to execute status = PsCreateSystemThread(&periodMeasureThreadHandle, THREAD_ALL_ACCESS, &objectAttributes, NULL, NULL, periodicMeasurePe, NULL); status = ObReferenceObjectByHandle(periodMeasureThreadHandle, 0, NULL, KernelMode, &periodicMeasureThread, NULL); ZwClose(periodMeasureThreadHandle); //don't need the handle anymore, ref will remain valid #endif } else { translations = (uint32) translationArr; // VMCALL to stop TLB splitting __asm { PUSHAD MOV EAX, VMCALL_END_SPLIT MOV EBX, translations _emit 0x0F // VMCALL _emit 0x01 _emit 0xC1 POPAD } if (LockedMdl != NULL) { pagingUnlockProcessMemory(proc, &apcstate, LockedMdl); } if (appCopy != NULL) { MmFreeContiguousMemory((PVOID) appCopy); } if (translationArr != NULL) { freeTranslationArray(translationArr); } targetCR3 = 0; #ifdef PERIODIC_MEASURE /* Stop the periodic measurement thread */ periodicMeasureThreadExecute = 0; // Apply brakes KeSetEvent(&periodicMeasureThreadWakeUp, 0, TRUE); // Cancel any current wait in the thread /* Wait for thread to stop */ KeWaitForSingleObject(periodicMeasureThread, Executive, KernelMode, FALSE, NULL); ObDereferenceObject(periodicMeasureThread); #endif peMapOutImageHeader(targetPePtr); targetPeVirt = NULL; } return; }
PVOID HalAllocateCommonBuffer( IN PADAPTER_OBJECT AdapterObject, IN ULONG Length, OUT PPHYSICAL_ADDRESS LogicalAddress, IN BOOLEAN CacheEnabled ) /*++ Routine Description: This function allocates the memory for a common buffer and maps so that it can be accessed by a master device and the CPU. Arguments: AdapterObject - Supplies a pointer to the adapter object used by this device. Length - Supplies the length of the common buffer to be allocated. LogicalAddress - Returns the logical address of the common buffer. CacheEnable - Indicates whether the memeory is cached or not. Return Value: Returns the virtual address of the common buffer. If the buffer cannot be allocated then NULL is returned. --*/ { PVOID virtualAddress; PVOID virtualAddress2; PHYSICAL_ADDRESS physicalAddress; UNREFERENCED_PARAMETER( CacheEnabled ); // // Assume below 16M // physicalAddress.HighPart = 0; physicalAddress.LowPart = MAXIMUM_PHYSICAL_ADDRESS-1; // // If the caller support 32bit addresses, and it's a master let // it have any memory below 4G // if (AdapterObject->Dma32BitAddresses && AdapterObject->MasterDevice) { physicalAddress.LowPart = 0xFFFFFFFF; } virtualAddress = MmAllocateContiguousMemory( Length, physicalAddress ); if (virtualAddress == NULL) { return(NULL); } *LogicalAddress = MmGetPhysicalAddress(virtualAddress); if (HalpBusType != MACHINE_TYPE_ISA || AdapterObject->MasterDevice) { return(virtualAddress); } // // This is an ISA system the common buffer cannot cross a 64 K bountry. // if ((LogicalAddress->LowPart + Length & ~0xFFFF) == (LogicalAddress->LowPart & ~0xFFFF)) { // // This buffer is ok so return it. // return(virtualAddress); } // // Try to allocate a buffer agian and see if this is good. // virtualAddress2 = MmAllocateContiguousMemory( Length, physicalAddress ); // // Free the first buffer. // MmFreeContiguousMemory(virtualAddress); if (virtualAddress2 == NULL) { return(NULL); } *LogicalAddress = MmGetPhysicalAddress(virtualAddress2); if ((LogicalAddress->LowPart + Length & ~0xFFFF) == (LogicalAddress->LowPart & ~0xFFFF)) { // // This buffer is ok so return it. // return(virtualAddress2); } // // Try our best but just could not do it. Free the buffer. // MmFreeContiguousMemory(virtualAddress2); return(NULL); }
/// <summary> /// Execute VMLAUNCH /// </summary> /// <param name="Vcpu">Virtyal CPU data</param> VOID VmxSubvertCPU( IN PVCPU Vcpu ) { PHYSICAL_ADDRESS phys = { 0 }; phys.QuadPart = MAXULONG64; // // Initialize all the VMX-related MSRs by reading their value // for (ULONG i = 0; i <= VMX_MSR( MSR_IA32_VMX_VMCS_ENUM ); i++) Vcpu->MsrData[i].QuadPart = __readmsr( MSR_IA32_VMX_BASIC + i ); // Secondary controls, if present if (g_Data->Features.SecondaryControls) Vcpu->MsrData[VMX_MSR( MSR_IA32_VMX_PROCBASED_CTLS2 )].QuadPart = __readmsr( MSR_IA32_VMX_PROCBASED_CTLS2 ); // True MSRs, if present if (g_Data->Features.TrueMSRs) for (ULONG i = VMX_MSR( MSR_IA32_VMX_TRUE_PINBASED_CTLS ); i <= VMX_MSR( MSR_IA32_VMX_TRUE_ENTRY_CTLS ); i++) Vcpu->MsrData[i].QuadPart = __readmsr( MSR_IA32_VMX_BASIC + i ); // VMFUNC, if present if(g_Data->Features.VMFUNC) Vcpu->MsrData[VMX_MSR( MSR_IA32_VMX_VMFUNC )].QuadPart = __readmsr( MSR_IA32_VMX_VMFUNC ); Vcpu->VMXON = MmAllocateContiguousMemory( sizeof( VMX_VMCS ), phys ); Vcpu->VMCS = MmAllocateContiguousMemory( sizeof( VMX_VMCS ), phys ); Vcpu->VMMStack = MmAllocateContiguousMemory( KERNEL_STACK_SIZE, phys ); if (!Vcpu->VMXON || !Vcpu->VMCS || !Vcpu->VMMStack) { DPRINT( "HyperBone: CPU %d: %s: Failed to allocate memory\n", CPU_IDX, __FUNCTION__ ); goto failed; } UtilProtectNonpagedMemory( Vcpu->VMXON, sizeof( VMX_VMCS ), PAGE_READWRITE ); UtilProtectNonpagedMemory( Vcpu->VMCS, sizeof( VMX_VMCS ), PAGE_READWRITE ); UtilProtectNonpagedMemory( Vcpu->VMMStack, KERNEL_STACK_SIZE, PAGE_READWRITE ); RtlZeroMemory( Vcpu->VMXON, sizeof( VMX_VMCS ) ); RtlZeroMemory( Vcpu->VMCS, sizeof( VMX_VMCS ) ); RtlZeroMemory( Vcpu->VMMStack, KERNEL_STACK_SIZE ); // Attempt to enter VMX root mode on this processor. if (VmxEnterRoot( Vcpu )) { // Initialize the VMCS, both guest and host state. VmxSetupVMCS( Vcpu ); // Setup EPT if(g_Data->Features.EPT) { if (!NT_SUCCESS( EptBuildIdentityMap( &Vcpu->EPT ) )) { DPRINT( "HyperBone: CPU %d: %s: Failed to build EPT identity map\n", CPU_IDX, __FUNCTION__ ); goto failedvmxoff; } EptEnable( Vcpu->EPT.PML4Ptr ); } // Record that VMX is now enabled Vcpu->VmxState = VMX_STATE_TRANSITION; // Setup various VMCS fields by VmxSetupVmcs. This will cause the // processor to jump to the return address of RtlCaptureContext in // VmxInitializeCPU, which called us. InterlockedIncrement( &g_Data->vcpus ); int res = __vmx_vmlaunch(); InterlockedDecrement( &g_Data->vcpus ); // If we got here, either VMCS setup failed in some way, or the launch // did not proceed as planned. Because VmxEnabled is not set to 1, this // will correctly register as a failure. Vcpu->VmxState = VMX_STATE_OFF; DPRINT( "HyperBone: CPU %d: %s: __vmx_vmlaunch failed with result %d\n", CPU_IDX, __FUNCTION__, res ); failedvmxoff: __vmx_off(); } failed:; if (Vcpu->VMXON) MmFreeContiguousMemory( Vcpu->VMXON ); if (Vcpu->VMCS) MmFreeContiguousMemory( Vcpu->VMCS ); if (Vcpu->VMMStack) MmFreeContiguousMemory( Vcpu->VMMStack ); Vcpu->VMXON = NULL; Vcpu->VMCS = NULL; Vcpu->VMMStack = NULL; }
/// <summary> /// Hook function /// </summary> /// <param name="pFunc">Function address</param> /// <param name="pHook">Hook address</param> /// /// <param name="Type">Hook type</param> /// <returns>Status code</returns> NTSTATUS PHHook( IN PVOID pFunc, IN PVOID pHook, IN HOOK_TYPE Type ) { PUCHAR CodePage = NULL; BOOLEAN Newpage = FALSE; PHYSICAL_ADDRESS phys = { 0 }; phys.QuadPart = MAXULONG64; // No CPU support if (!g_Data->EPTSupported || !g_Data->EPTExecOnlySupported) return STATUS_NOT_SUPPORTED; // Check if page is already hooked PPAGE_HOOK_ENTRY pEntry = PHGetHookEntryByPage( pFunc, DATA_PAGE ); if (pEntry != NULL) { CodePage = pEntry->CodePageVA; } else { CodePage = MmAllocateContiguousMemory( PAGE_SIZE, phys ); Newpage = TRUE; } if (CodePage == NULL) return STATUS_INSUFFICIENT_RESOURCES; PPAGE_HOOK_ENTRY pHookEntry = ExAllocatePoolWithTag( NonPagedPool, sizeof( PAGE_HOOK_ENTRY ), HB_POOL_TAG ); if (pHookEntry == NULL) return STATUS_INSUFFICIENT_RESOURCES; RtlZeroMemory( pHookEntry, sizeof( PAGE_HOOK_ENTRY ) ); RtlCopyMemory( CodePage, PAGE_ALIGN( pFunc ), PAGE_SIZE ); // Copy original code NTSTATUS status = PHpCopyCode( pFunc, pHookEntry->OriginalData, &pHookEntry->OriginalSize ); if (!NT_SUCCESS( status )) { ExFreePoolWithTag( pHookEntry, HB_POOL_TAG ); return status; } ULONG_PTR page_offset = (ULONG_PTR)pFunc - (ULONG_PTR)PAGE_ALIGN( pFunc ); // TODO: atomic memory patching, i.e. with other CPUs spinlocked JUMP_THUNK thunk = { 0 }; PHpInitJumpThunk( &thunk, (ULONG64)pHook ); memcpy( CodePage + page_offset, &thunk, sizeof( thunk ) ); pHookEntry->Type = Type; pHookEntry->OriginalPtr = pFunc; pHookEntry->DataPageVA = PAGE_ALIGN( pFunc ); pHookEntry->DataPagePFN = PFN( MmGetPhysicalAddress( pFunc ).QuadPart ); pHookEntry->CodePageVA = CodePage; pHookEntry->CodePagePFN = PFN( MmGetPhysicalAddress( CodePage ).QuadPart ); // Add to list if (g_PageList.Flink == NULL) InitializeListHead( &g_PageList ); InsertTailList( &g_PageList, &pHookEntry->Link ); // Create EPT page translation if (Newpage) { HOOK_CONTEXT ctx = { 0 }; ctx.Hook = TRUE; ctx.DataPagePFN = pHookEntry->DataPagePFN; ctx.CodePagePFN = pHookEntry->CodePagePFN; ctx.Type = Type; KeGenericCallDpc( PHpHookCallbackDPC, &ctx ); } return STATUS_SUCCESS; }