// Handles MTF VM-exit. Restores the last breakpoint event, re-enables stealth // breakpoint and clears MTF; _Use_decl_annotations_ void SbpHandleMonitorTrapFlag(EptData* ept_data) { NT_VERIFY(SbppIsSbpActive()); const auto info = SbppRestoreLastPatchInfo(); SbppEnablePageShadowingForExec(*info, ept_data); SbppSetMonitorTrapFlag(false); }
// Deal with EPT violation VM-exit. _Use_decl_annotations_ void EptHandleEptViolation(EptData *ept_data) { const EptViolationQualification exit_qualification = { UtilVmRead(VmcsField::kExitQualification)}; const auto fault_pa = UtilVmRead64(VmcsField::kGuestPhysicalAddress); const auto fault_va = exit_qualification.fields.valid_guest_linear_address ? UtilVmRead(VmcsField::kGuestLinearAddress) : 0; if (!exit_qualification.fields.ept_readable && !exit_qualification.fields.ept_writeable && !exit_qualification.fields.ept_executable) { const auto ept_entry = EptGetEptPtEntry(ept_data, fault_pa); if (!ept_entry || !ept_entry->all) { // EPT entry miss. It should be device memory. HYPERPLATFORM_PERFORMANCE_MEASURE_THIS_SCOPE(); if (!IsReleaseBuild()) { NT_VERIFY(EptpIsDeviceMemory(fault_pa)); } EptpConstructTables(ept_data->ept_pml4, 4, fault_pa, ept_data); UtilInveptAll(); return; } } HYPERPLATFORM_LOG_DEBUG_SAFE("[IGNR] OTH VA = %p, PA = %016llx", fault_va, fault_pa); }
VOID Ucm_EvtSetDataRoleCompleted ( _In_ UCSI_CONTROL Command, _In_ PVOID Context, _Inout_ PPPM_COMMAND_ACK_PARAMS CommandAckParams ) /*++ Routine Description: Set data role command completion routine. Notifies UCM that the power direction has changed. Arguments: Command - The UCSI command that was completed. In this case, it should be only SetUor.UsbOperationRole. Context - Platform policy manager context object. CommandAckParams - UCSI command acknowledge parameters. --*/ { UCM_DATA_ROLE dataRole; PPPM_CONTEXT ppmCtx; WDFDEVICE device; PPPM_CONNECTOR connector; BOOLEAN success; UNREFERENCED_PARAMETER(CommandAckParams); PAGED_CODE(); TRACE_FUNC_ENTRY(TRACE_FLAG_UCMNOTIFICATIONS); ppmCtx = (PPPM_CONTEXT)Context; device = Context_GetWdfDevice(ppmCtx); connector = Ppm_GetConnector(ppmCtx, Command.SetUor.ConnectorNumber); NT_VERIFY(Convert((UCSI_USB_OPERATION_ROLE)Command.SetUor.UsbOperationRole, dataRole)); success = UCSI_CMD_SUCCEEDED(ppmCtx->UcsiDataBlock->CCI); if (success) { TRACE_INFO(TRACE_FLAG_UCMNOTIFICATIONS, "[Device: 0x%p] Data role successfully changed to %!UCM_DATA_ROLE!", device, dataRole); } else { TRACE_ERROR(TRACE_FLAG_UCMNOTIFICATIONS, "[Device: 0x%p] Data role change to %!UCM_DATA_ROLE! failed", device, dataRole); } // // Notify UCM that the data direction has changed. // UcmConnectorDataDirectionChanged(connector->Handle, success, dataRole); TRACE_FUNC_EXIT(TRACE_FLAG_UCMNOTIFICATIONS); }
// Terminates a given process as well as its child process, and wait for // terminatation of the given process _Use_decl_annotations_ static NTSTATUS EopmonpTerminateProcessTree( HANDLE process_handle, HANDLE pid) { PAGED_CODE(); auto status = ZwTerminateProcess(process_handle, 0); HYPERPLATFORM_LOG_DEBUG( "Exploitation detected. Process %Iu is being terminated (status = %08x).", pid, status); if (status == STATUS_PROCESS_IS_TERMINATING) { return status; } status = EopmonpForEachProcess(EopmonpTerminateProcessIfChild, pid); NT_VERIFY(NT_SUCCESS(status)); status = ZwWaitForSingleObject(process_handle, FALSE, nullptr); NT_VERIFY(NT_SUCCESS(status)); return status; }
// Deal with L2 EPT violation VM-exit. _Use_decl_annotations_ void EptHandleEptViolationEx(EptData *ept_data, EptData *ept_data02, ULONG_PTR guest_pa, bool is_range_of_ept12) { const EptViolationQualification exit_qualification = { UtilVmRead(VmcsField::kExitQualification) }; ULONG_PTR fault_pa = 0; if (!guest_pa) { fault_pa = UtilVmRead64(VmcsField::kGuestPhysicalAddress); } else { fault_pa = guest_pa; } const auto fault_va = reinterpret_cast<void *>( exit_qualification.fields.valid_guest_linear_address ? UtilVmRead(VmcsField::kGuestLinearAddress) : 0); //GuestPhysicalAddress will be the guest physical adderss of EPT1-2 Entry , we disable it write in L2 first initial if (!exit_qualification.fields.ept_readable && !exit_qualification.fields.ept_writeable && !exit_qualification.fields.ept_executable) { const auto ept_entry = EptGetEptPtEntry(ept_data, fault_pa); if (!ept_entry || !ept_entry->all) { // EPT entry miss. It should be device memory. HYPERPLATFORM_PERFORMANCE_MEASURE_THIS_SCOPE(); if (!IsReleaseBuild()) { NT_VERIFY(EptpIsDeviceMemory(fault_pa)); } EptpConstructTables(ept_data->ept_pml4, 4, fault_pa, ept_data); UtilInveptGlobal(); return; } } if (!exit_qualification.fields.ept_writeable && is_range_of_ept12) { EptCommonEntry* Ept01Pte = EptGetEptPtEntry(ept_data, UtilVmRead64(VmcsField::kGuestPhysicalAddress)); if (Ept01Pte) { EptCommonEntry* entry = (EptCommonEntry*)UtilVaFromPa(UtilVmRead64(VmcsField::kGuestPhysicalAddress)); Ept01Pte->fields.write_access = true; HYPERPLATFORM_LOG_DEBUG_SAFE("Faced non-writable address but it is readble. :%p %p", UtilVmRead64(VmcsField::kGuestPhysicalAddress), entry->fields.physial_address); UtilInveptGlobal(); } } }
// Terminates DdiMon _Use_decl_annotations_ EXTERN_C void SbpTermination() { PAGED_CODE(); auto ptrs = g_sbpp_breakpoints; auto status = UtilVmCall(HypercallNumber::kDdimonDisablePageShadowing, ptrs); NT_VERIFY(NT_SUCCESS(status)); UtilSleep(500); g_sbpp_breakpoints = nullptr; delete ptrs; }
// Converts a pool tag in integer to a printable string _Use_decl_annotations_ static std::array<char, 5> DdimonpTagToString( ULONG tag_value) { PoolTag tag = {tag_value}; for (auto& c : tag.chars) { if (!c && isspace(c)) { c = ' '; } if (!isprint(c)) { c = '.'; } } std::array<char, 5> str; auto status = RtlStringCchPrintfA(str.data(), str.size(), "%c%c%c%c", tag.chars[0], tag.chars[1], tag.chars[2], tag.chars[3]); NT_VERIFY(NT_SUCCESS(status)); return str; }
// Terminates a process if it is created from a dodgy process _Use_decl_annotations_ static bool EopmonpTerminateProcessIfChild( HANDLE pid, void* context) { PAGED_CODE(); const auto dodgy_pid = reinterpret_cast<HANDLE>(context); const auto process_handle = EopmonpOpenProcess(pid); if (!process_handle) { return true; } // Is this process created from the dodgy process? const auto parent_pid = EopmonpGetProcessParentProcessIdByHandle(process_handle); if (parent_pid != dodgy_pid) { goto exit; } // Is this process created later than the dodgy process? const auto create_time = EopmonpGetProcessCreateTimeQuadPart(pid); const auto parent_create_time = EopmonpGetProcessCreateTimeQuadPart(dodgy_pid); if (!create_time || !parent_create_time || create_time <= parent_create_time) { goto exit; } // Yes, terminate this process as well as its child processes auto status = ZwTerminateProcess(process_handle, 0); HYPERPLATFORM_LOG_DEBUG( "Exploitation detected. Process %Iu is being terminated (status = %08x).", pid, status); status = EopmonpForEachProcess(EopmonpTerminateProcessIfChild, pid); NT_VERIFY(NT_SUCCESS(status)); exit:; ZwClose(process_handle); return true; }
BOOLEAN CompareFileName(PUNICODE_STRING FileName, PINDEX_ENTRY_ATTRIBUTE IndexEntry, BOOLEAN DirSearch) { BOOLEAN Ret, Alloc = FALSE; UNICODE_STRING EntryName; EntryName.Buffer = IndexEntry->FileName.Name; EntryName.Length = EntryName.MaximumLength = IndexEntry->FileName.NameLength * sizeof(WCHAR); if (DirSearch) { UNICODE_STRING IntFileName; if (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX) { NT_VERIFY(NT_SUCCESS(RtlUpcaseUnicodeString(&IntFileName, FileName, TRUE))); Alloc = TRUE; } else { IntFileName = *FileName; } Ret = FsRtlIsNameInExpression(&IntFileName, &EntryName, (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX), NULL); if (Alloc) { RtlFreeUnicodeString(&IntFileName); } return Ret; } else { return (RtlCompareUnicodeString(FileName, &EntryName, (IndexEntry->FileName.NameType != NTFS_FILE_NAME_POSIX)) == 0); } }
NTSTATUS PostProcessSelectConfig( IN PUSB_FDO_CONTEXT fdoContext, IN PURB Urb) { PUSB_CONFIGURATION_DESCRIPTOR config = Urb->UrbSelectConfiguration.ConfigurationDescriptor; NTSTATUS Status = STATUS_UNSUCCESSFUL; // // config can be null if the client driver has reset the configuration // if (config) { fdoContext->CurrentConfigValue = config->bConfigurationValue; SetConfigPointers(fdoContext); if (NT_VERIFY(fdoContext->InterfaceDescriptors)) { Urb->UrbSelectConfiguration.ConfigurationHandle = fdoContext->ConfigurationDescriptor; Status = STATUS_SUCCESS; } } else { fdoContext->CurrentConfigValue = 0; // unconfigured SetConfigPointers(fdoContext); Status = STATUS_SUCCESS; } ASSERT(fdoContext->ConfigBusy); fdoContext->ConfigBusy = FALSE; TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DPC, __FUNCTION__": returns Status %x\n", Status); return Status; }
NTSTATUS NTAPI AfdPacketSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { NTSTATUS Status = STATUS_SUCCESS; PTDI_CONNECTION_INFORMATION TargetAddress; PFILE_OBJECT FileObject = IrpSp->FileObject; PAFD_FCB FCB = FileObject->FsContext; PAFD_SEND_INFO_UDP SendReq; KPROCESSOR_MODE LockMode; UNREFERENCED_PARAMETER(DeviceObject); AFD_DbgPrint(MID_TRACE,("Called on %p\n", FCB)); if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp ); FCB->EventSelectDisabled &= ~AFD_EVENT_SEND; /* Check that the socket is bound */ if( FCB->State != SOCKET_STATE_BOUND && FCB->State != SOCKET_STATE_CREATED) { AFD_DbgPrint(MIN_TRACE,("Invalid socket state\n")); return UnlockAndMaybeComplete(FCB, STATUS_INVALID_PARAMETER, Irp, 0); } if (FCB->SendClosed) { AFD_DbgPrint(MIN_TRACE,("No more sends\n")); return UnlockAndMaybeComplete(FCB, STATUS_FILE_CLOSED, Irp, 0); } if( !(SendReq = LockRequest( Irp, IrpSp, FALSE, &LockMode )) ) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0); if (FCB->State == SOCKET_STATE_CREATED) { if( FCB->LocalAddress ) ExFreePool( FCB->LocalAddress ); FCB->LocalAddress = TaBuildNullTransportAddress( ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress)-> Address[0].AddressType ); if( FCB->LocalAddress ) { Status = WarmSocketForBind( FCB, AFD_SHARE_WILDCARD ); if( NT_SUCCESS(Status) ) FCB->State = SOCKET_STATE_BOUND; else return UnlockAndMaybeComplete( FCB, Status, Irp, 0 ); } else return UnlockAndMaybeComplete ( FCB, STATUS_NO_MEMORY, Irp, 0 ); } SendReq->BufferArray = LockBuffers( SendReq->BufferArray, SendReq->BufferCount, NULL, NULL, FALSE, FALSE, LockMode ); if( !SendReq->BufferArray ) return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION, Irp, 0 ); AFD_DbgPrint (MID_TRACE,("RemoteAddress #%d Type %u\n", ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress)-> TAAddressCount, ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress)-> Address[0].AddressType)); Status = TdiBuildConnectionInfo( &TargetAddress, ((PTRANSPORT_ADDRESS)SendReq->TdiConnection.RemoteAddress) ); /* Check the size of the Address given ... */ if( NT_SUCCESS(Status) ) { FCB->PollState &= ~AFD_EVENT_SEND; Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND); if (Status == STATUS_PENDING) { Status = TdiSendDatagram(&FCB->SendIrp.InFlightRequest, FCB->AddressFile.Object, SendReq->BufferArray[0].buf, SendReq->BufferArray[0].len, TargetAddress, PacketSocketSendComplete, FCB); if (Status != STATUS_PENDING) { NT_VERIFY(RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]) == &Irp->Tail.Overlay.ListEntry); Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; (void)IoSetCancelRoutine(Irp, NULL); UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE); UnlockRequest(Irp, IoGetCurrentIrpStackLocation(Irp)); IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); } } ExFreePool(TargetAddress); SocketStateUnlock(FCB); return STATUS_PENDING; } else { UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE); return UnlockAndMaybeComplete( FCB, Status, Irp, 0 ); } }
NTSTATUS NTAPI AfdConnectedSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, BOOLEAN Short) { NTSTATUS Status = STATUS_SUCCESS; PFILE_OBJECT FileObject = IrpSp->FileObject; PAFD_FCB FCB = FileObject->FsContext; PAFD_SEND_INFO SendReq; UINT TotalBytesCopied = 0, i, SpaceAvail = 0, BytesCopied, SendLength; KPROCESSOR_MODE LockMode; UNREFERENCED_PARAMETER(DeviceObject); UNREFERENCED_PARAMETER(Short); AFD_DbgPrint(MID_TRACE,("Called on %p\n", FCB)); if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp ); FCB->EventSelectDisabled &= ~AFD_EVENT_SEND; if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS ) { PAFD_SEND_INFO_UDP SendReq; PTDI_CONNECTION_INFORMATION TargetAddress; /* Check that the socket is bound */ if( FCB->State != SOCKET_STATE_BOUND || !FCB->RemoteAddress ) { AFD_DbgPrint(MIN_TRACE,("Invalid parameter\n")); return UnlockAndMaybeComplete( FCB, STATUS_INVALID_PARAMETER, Irp, 0 ); } if( !(SendReq = LockRequest( Irp, IrpSp, FALSE, &LockMode )) ) return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0 ); /* Must lock buffers before handing off user data */ SendReq->BufferArray = LockBuffers( SendReq->BufferArray, SendReq->BufferCount, NULL, NULL, FALSE, FALSE, LockMode ); if( !SendReq->BufferArray ) { return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION, Irp, 0 ); } Status = TdiBuildConnectionInfo( &TargetAddress, FCB->RemoteAddress ); if( NT_SUCCESS(Status) ) { FCB->PollState &= ~AFD_EVENT_SEND; Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND); if (Status == STATUS_PENDING) { Status = TdiSendDatagram(&FCB->SendIrp.InFlightRequest, FCB->AddressFile.Object, SendReq->BufferArray[0].buf, SendReq->BufferArray[0].len, TargetAddress, PacketSocketSendComplete, FCB); if (Status != STATUS_PENDING) { NT_VERIFY(RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]) == &Irp->Tail.Overlay.ListEntry); Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; (void)IoSetCancelRoutine(Irp, NULL); UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE); UnlockRequest(Irp, IoGetCurrentIrpStackLocation(Irp)); IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); } } ExFreePool( TargetAddress ); SocketStateUnlock(FCB); return STATUS_PENDING; } else { UnlockBuffers(SendReq->BufferArray, SendReq->BufferCount, FALSE); return UnlockAndMaybeComplete( FCB, Status, Irp, 0 ); } } if (FCB->PollState & AFD_EVENT_CLOSE) { AFD_DbgPrint(MIN_TRACE,("Connection reset by remote peer\n")); /* This is an unexpected remote disconnect */ return UnlockAndMaybeComplete(FCB, FCB->PollStatus[FD_CLOSE_BIT], Irp, 0); } if (FCB->PollState & AFD_EVENT_ABORT) { AFD_DbgPrint(MIN_TRACE,("Connection aborted\n")); /* This is an abortive socket closure on our side */ return UnlockAndMaybeComplete(FCB, FCB->PollStatus[FD_CLOSE_BIT], Irp, 0); } if (FCB->SendClosed) { AFD_DbgPrint(MIN_TRACE,("No more sends\n")); /* This is a graceful send closure */ return UnlockAndMaybeComplete(FCB, STATUS_FILE_CLOSED, Irp, 0); } if( !(SendReq = LockRequest( Irp, IrpSp, FALSE, &LockMode )) ) return UnlockAndMaybeComplete ( FCB, STATUS_NO_MEMORY, Irp, 0 ); SendReq->BufferArray = LockBuffers( SendReq->BufferArray, SendReq->BufferCount, NULL, NULL, FALSE, FALSE, LockMode ); if( !SendReq->BufferArray ) { return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION, Irp, 0 ); } AFD_DbgPrint(MID_TRACE,("Socket state %u\n", FCB->State)); if( FCB->State != SOCKET_STATE_CONNECTED ) { AFD_DbgPrint(MID_TRACE,("Socket not connected\n")); UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); return UnlockAndMaybeComplete( FCB, STATUS_INVALID_CONNECTION, Irp, 0 ); } AFD_DbgPrint(MID_TRACE,("FCB->Send.BytesUsed = %u\n", FCB->Send.BytesUsed)); SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed; AFD_DbgPrint(MID_TRACE,("We can accept %u bytes\n", SpaceAvail)); /* Count the total transfer size */ SendLength = 0; for (i = 0; i < SendReq->BufferCount; i++) { SendLength += SendReq->BufferArray[i].len; } /* Make sure we've got the space */ if (SendLength > SpaceAvail) { /* Blocking sockets have to wait here */ if (SendLength <= FCB->Send.Size && !((SendReq->AfdFlags & AFD_IMMEDIATE) || (FCB->NonBlocking))) { FCB->PollState &= ~AFD_EVENT_SEND; return LeaveIrpUntilLater(FCB, Irp, FUNCTION_SEND); } /* Check if we can send anything */ if (SpaceAvail == 0) { FCB->PollState &= ~AFD_EVENT_SEND; /* Non-overlapped sockets will fail if we can send nothing */ if (!(SendReq->AfdFlags & AFD_OVERLAPPED)) { UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); return UnlockAndMaybeComplete( FCB, STATUS_CANT_WAIT, Irp, 0 ); } else { /* Overlapped sockets just pend */ return LeaveIrpUntilLater(FCB, Irp, FUNCTION_SEND); } } } for ( i = 0; SpaceAvail > 0 && i < SendReq->BufferCount; i++ ) { BytesCopied = MIN(SendReq->BufferArray[i].len, SpaceAvail); AFD_DbgPrint(MID_TRACE,("Copying Buffer %u, %p:%u to %p\n", i, SendReq->BufferArray[i].buf, BytesCopied, FCB->Send.Window + FCB->Send.BytesUsed)); RtlCopyMemory(FCB->Send.Window + FCB->Send.BytesUsed, SendReq->BufferArray[i].buf, BytesCopied); TotalBytesCopied += BytesCopied; SpaceAvail -= BytesCopied; FCB->Send.BytesUsed += BytesCopied; } Irp->IoStatus.Information = TotalBytesCopied; if( TotalBytesCopied == 0 ) { AFD_DbgPrint(MID_TRACE,("Empty send\n")); UnlockBuffers( SendReq->BufferArray, SendReq->BufferCount, FALSE ); return UnlockAndMaybeComplete ( FCB, STATUS_SUCCESS, Irp, TotalBytesCopied ); } if (SpaceAvail) { FCB->PollState |= AFD_EVENT_SEND; FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS; PollReeval( FCB->DeviceExt, FCB->FileObject ); } else { FCB->PollState &= ~AFD_EVENT_SEND; } /* We use the IRP tail for some temporary storage here */ Irp->Tail.Overlay.DriverContext[3] = (PVOID)Irp->IoStatus.Information; Status = QueueUserModeIrp(FCB, Irp, FUNCTION_SEND); if (Status == STATUS_PENDING && !FCB->SendIrp.InFlightRequest) { TdiSend(&FCB->SendIrp.InFlightRequest, FCB->Connection.Object, 0, FCB->Send.Window, FCB->Send.BytesUsed, SendComplete, FCB); } SocketStateUnlock(FCB); return STATUS_PENDING; }