HyperDbg Debugger
Loading...
Searching...
No Matches
IdtEmulation.c File Reference

Handlers of Guest's IDT Emulator. More...

#include "pch.h"

Functions

VOID IdtEmulationQueryIdtEntriesRequest (PINTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS IdtQueryRequest, BOOLEAN ReadFromVmxRoot)
 Perform query for IDT entries.
VOID IdtEmulationCreateInterruptGate (PVOID Handler, SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 *Entry)
 Create an interrupt gate that points to the supplied interrupt handler.
VOID IdtEmulationPrepareHostIdt (_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
 Prepare Host IDT.
VOID IdtEmulationhandleHostInterrupt (_Inout_ INTERRUPT_TRAP_FRAME *IntrTrapFrame)
 Handle Page-fault exception bitmap VM-exits.
VOID IdtEmulationHandlePageFaults (_Inout_ VIRTUAL_MACHINE_STATE *VCpu, _In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit)
 Handle Page-fault exception bitmap VM-exits.
VOID IdtEmulationHandleExceptionAndNmi (_Inout_ VIRTUAL_MACHINE_STATE *VCpu, _In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit)
 Handle NMI and exception vm-exits.
BOOLEAN IdtEmulationInjectInterruptWhenInterruptWindowIsOpen (_Inout_ VIRTUAL_MACHINE_STATE *VCpu, _In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit)
 if the guest is not interruptible, then we save the details of each interrupt so we can re-inject them to the guest whenever the interrupt window is open
VOID IdtEmulationHandleExternalInterrupt (_Inout_ VIRTUAL_MACHINE_STATE *VCpu, _In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit)
 external-interrupt vm-exit handler
VOID IdtEmulationHandleNmiWindowExiting (_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
 Handle NMI-window exitings.
BOOLEAN IdtEmulationInjectPageFaultWhenInterruptWindowsIsOpen (_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
 Injects a page-fault when interrupt window is open.
VOID IdtEmulationHandleInterruptWindowExiting (_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
 Handle interrupt-window exitings.

Detailed Description

Handlers of Guest's IDT Emulator.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Version
0.1
Date
2020-06-10

Function Documentation

◆ IdtEmulationCreateInterruptGate()

VOID IdtEmulationCreateInterruptGate ( PVOID Handler,
SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 * Entry )

Create an interrupt gate that points to the supplied interrupt handler.

Parameters
VCpuThe virtual processor's state
Entry
Returns
VOID
74{
75 // SEGMENT_SELECTOR HostCsSelector = {0, 0, 1};
76 //
77 // Entry->InterruptStackTable = 0;
78 // Entry->SegmentSelector = HostCsSelector.AsUInt;
79 // Entry->MustBeZero0 = 0;
80 // Entry->Type = SEGMENT_DESCRIPTOR_TYPE_INTERRUPT_GATE;
81 // Entry->MustBeZero1 = 0;
82 // Entry->DescriptorPrivilegeLevel = 0;
83 // Entry->Present = 1;
84 // Entry->Reserved = 0;
85
86 UINT64 Offset = (UINT64)Handler;
87 Entry->OffsetLow = (Offset >> 0) & 0xFFFF;
88 Entry->OffsetMiddle = (Offset >> 16) & 0xFFFF;
89 Entry->OffsetHigh = (Offset >> 32) & 0xFFFFFFFF;
90
91#if USE_INTERRUPT_STACK_TABLE == TRUE
92
93 //
94 // Use first index (IST1)
95 //
96 Entry->InterruptStackTable = 1;
97
98#else
99
100 //
101 // Make sure to unset IST since we didn't use a separate stack pointer
102 // on TSS entry at GDT
103 //
104 Entry->InterruptStackTable = 0;
105
106#endif // USE_INTERRUPT_STACK_TABLE == TRUE
107}

◆ IdtEmulationHandleExceptionAndNmi()

VOID IdtEmulationHandleExceptionAndNmi ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu,
_In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit )

Handle NMI and exception vm-exits.

Parameters
VCpuThe virtual processor's state
InterruptExitinterrupt exit information
Returns
VOID
338{
339 //
340 // Exception or non-maskable interrupt (NMI). Either:
341 // 1: Guest software caused an exception and the bit in the exception bitmap associated with exception's vector was set to 1
342 // 2: An NMI was delivered to the logical processor and the "NMI exiting" VM-execution control was 1.
343 //
344 // VMCS_VMEXIT_INTERRUPTION_INFORMATION shows the exit information about event that occurred and causes this exit
345 // Don't forget to read VMCS_VMEXIT_INTERRUPTION_ERROR_CODE in the case of re-injectiong event
346 //
347
348 switch (InterruptExit.Vector)
349 {
351
352 //
353 // Handle software breakpoints
354 //
355 {
356 UINT64 GuestRip = NULL64_ZERO;
357 BYTE TargetMem = NULL_ZERO;
358
359 VmxVmread64P(VMCS_GUEST_RIP, &GuestRip);
360
361 MemoryMapperReadMemorySafe(GuestRip, &TargetMem, sizeof(BYTE));
362
363 if (!EptCheckAndHandleBreakpoint(VCpu) || TargetMem == 0xcc)
364 {
366 {
367 //
368 // Don't increment rip
369 //
371
372 //
373 // Kernel debugger (debugger-mode) is not attached, re-inject the breakpoint
374 //
376 }
377 }
378 }
379
380 break;
381
383
384 //
385 // Handle the #UD, checking if this exception was intentional.
386 //
387 if (!SyscallHookHandleUD(VCpu))
388 {
389 //
390 // If this #UD was found to be unintentional, inject a #UD interruption into the guest.
391 //
393 }
394
395 break;
396
398
399 //
400 // Handle page-faults (#PFs)
401 //
402 IdtEmulationHandlePageFaults(VCpu, InterruptExit);
403
404 break;
405
407
408 //
409 // Check if syscall callback is enabled and if so, then we need to
410 // check whether the this trap flag is set because of intercepting
411 // the result of a system-call or not
412 //
415 HANDLE_TO_UINT32(PsGetCurrentProcessId()),
416 HANDLE_TO_UINT32(PsGetCurrentThreadId())))
417 {
418 //
419 // Being here means that this #DB was caused by a trap flag of
420 // the system-call in the syscall callback, so no need to further handle
421 // it (nothing to do)
422 //
423 }
425 {
426 //
427 // It's not because of thread change detection, so re-inject it
428 //
429 EventInjectInterruptOrException(InterruptExit);
430 }
431
432 break;
433
435
436 if (VCpu->EnableExternalInterruptsOnContinue ||
437 VCpu->EnableExternalInterruptsOnContinueMtf ||
438 VCpu->InstrumentationStepInMtf)
439 {
440 //
441 // Ignore the nmi
442 //
443 }
444 else
445 {
446 //
447 // Re-inject the interrupt/exception because it doesn't relate to us
448 //
449 EventInjectInterruptOrException(InterruptExit);
450 }
451
452 break;
453
454 default:
455
456 //
457 // Re-inject the interrupt/exception, nothing special to handle
458 //
459 EventInjectInterruptOrException(InterruptExit);
460
461 break;
462 }
463}
BOOLEAN DebuggingCallbackHandleDebugBreakpointException(UINT32 CoreId)
routine callback to handle debug breakpoint exception
Definition Callback.c:252
BOOLEAN DebuggingCallbackHandleBreakpointException(UINT32 CoreId)
routine callback to handle breakpoint exception
Definition Callback.c:231
_Use_decl_annotations_ BOOLEAN SyscallHookHandleUD(VIRTUAL_MACHINE_STATE *VCpu)
Detect whether the UD was because of Syscall or Sysret or not.
Definition EferHook.c:267
BOOLEAN EptCheckAndHandleBreakpoint(VIRTUAL_MACHINE_STATE *VCpu)
Check if the breakpoint vm-exit relates to EPT hook or not.
Definition Ept.c:1317
VOID EventInjectInterruptOrException(_In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit)
re-inject interrupt or exception to the guest
Definition Events.c:155
VOID EventInjectUndefinedOpcode(VIRTUAL_MACHINE_STATE *VCpu)
Inject UD to the guest (Invalid Opcode - Undefined Opcode).
Definition Events.c:79
VOID EventInjectBreakpoint()
Inject BP to the guest (Event Injection).
Definition Events.c:46
VOID HvSuppressRipIncrement(VIRTUAL_MACHINE_STATE *VCpu)
Suppress the incrementation of RIP.
Definition Hv.c:320
VOID IdtEmulationHandlePageFaults(_Inout_ VIRTUAL_MACHINE_STATE *VCpu, _In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit)
Handle Page-fault exception bitmap VM-exits.
Definition IdtEmulation.c:296
#define HANDLE_TO_UINT32(_var)
Definition MetaMacros.h:39
UCHAR VmxVmread64P(size_t Field, UINT64 *FieldValue)
VMX VMREAD instruction (64-bit, pointer variant).
Definition PlatformIntrinsicsVmx.c:207
BOOLEAN SyscallCallbackCheckAndHandleAfterSyscallTrapFlags(VIRTUAL_MACHINE_STATE *VCpu, UINT32 ProcessId, UINT32 ThreadId)
Handle the trap flags as the result of interception of the return of the system-call.
Definition SyscallCallback.c:285
#define NULL_ZERO
Definition BasicTypes.h:110
unsigned char BYTE
Definition BasicTypes.h:40
#define NULL64_ZERO
Definition BasicTypes.h:111
@ EXCEPTION_VECTOR_UNDEFINED_OPCODE
Definition Events.h:30
@ EXCEPTION_VECTOR_NMI
Definition Events.h:26
@ EXCEPTION_VECTOR_DEBUG_BREAKPOINT
Definition Events.h:25
@ EXCEPTION_VECTOR_PAGE_FAULT
Definition Events.h:38
@ EXCEPTION_VECTOR_BREAKPOINT
Definition Events.h:27
IMPORT_EXPORT_VMM BOOLEAN MemoryMapperReadMemorySafe(_In_ UINT64 VaAddressToRead, _Inout_ PVOID BufferToSaveMemory, _In_ SIZE_T SizeToRead)
BOOLEAN g_SyscallCallbackStatus
Shows whether the syscall callback is enabled or not.
Definition GlobalVariables.h:118

◆ IdtEmulationHandleExternalInterrupt()

VOID IdtEmulationHandleExternalInterrupt ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu,
_In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit )

external-interrupt vm-exit handler

Parameters
VCpuThe virtual processor's state
InterruptExitinterrupt info from vm-exit
Returns
VOID
514{
515 BOOLEAN Interruptible = TRUE;
516 VMX_INTERRUPTIBILITY_STATE InterruptibilityState = {0};
517 RFLAGS GuestRflags = {0};
518
519 //
520 // In order to enable External Interrupt Exiting we have to set
521 // IA32_VMX_PINBASED_CTLS_EXTERNAL_INTERRUPT_EXITING_FLAG in vmx
522 // pin-based controls (PIN_BASED_VM_EXEC_CONTROL) and also
523 // we should enable IA32_VMX_EXIT_CTLS_ACKNOWLEDGE_INTERRUPT_ON_EXIT_FLAG
524 // on vmx vm-exit controls (VMCS_CTRL_VMEXIT_CONTROLS), also this function
525 // might not always be successful if the guest is not in the interruptible
526 // state so it wait for and interrupt-window exiting to re-inject
527 // the interrupt into the guest
528 //
529 if (VCpu->EnableExternalInterruptsOnContinue ||
530 VCpu->EnableExternalInterruptsOnContinueMtf)
531 {
532 //
533 // Ignore the interrupt as it's suppressed because of instrumentation step-in
534 //
535
536 //
537 // During developing HyperDbg, we realized that if we just ignore the interrupts completely
538 // while we are waiting on 'i' instrumentation step-in command, then the serial device becomes
539 // unresponsive, to solve this issue we hold the details of interrupts so we can re-inject
540 // and process them when we decide to continue the debuggee (guest interrupt windows is open)
541 // this way, the serial device works normally and won't become unresponsive
542 //
544
545 //
546 // avoid incrementing rip
547 //
549 }
550
551 else if (InterruptExit.Valid && InterruptExit.InterruptionType == INTERRUPT_TYPE_EXTERNAL_INTERRUPT)
552 {
553 VmxVmread64P(VMCS_GUEST_RFLAGS, &GuestRflags.AsUInt);
554 VmxVmread32P(VMCS_GUEST_INTERRUPTIBILITY_STATE, &InterruptibilityState.AsUInt);
555
556 //
557 // External interrupts cannot be injected into the
558 // guest if guest isn't interruptible (e.g.: guest
559 // is blocked by "mov ss", or EFLAGS.IF == 0).
560 //
561 Interruptible = GuestRflags.InterruptEnableFlag && !InterruptibilityState.BlockingByMovSs;
562
563 if (Interruptible)
564 {
565 //
566 // Re-inject the interrupt/exception
567 //
568 EventInjectInterruptOrException(InterruptExit);
569 }
570 else
571 {
572 //
573 // We can't inject interrupt because the guest's state is not interruptible
574 // we have to queue it an re-inject it when the interrupt window is opened!
575 //
577
578 //
579 // Enable Interrupt-window exiting.
580 //
582 }
583
584 //
585 // avoid incrementing rip
586 //
588 }
589 else
590 {
591 Interruptible = FALSE;
592
593 LogError("Err, why we are here? it's a vm-exit due to the external"
594 "interrupt and its type is not external interrupt? weird!");
595 }
596}
VOID HvSetInterruptWindowExiting(BOOLEAN Set)
Set Interrupt-window exiting.
Definition Hv.c:650
BOOLEAN IdtEmulationInjectInterruptWhenInterruptWindowIsOpen(_Inout_ VIRTUAL_MACHINE_STATE *VCpu, _In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit)
if the guest is not interruptible, then we save the details of each interrupt so we can re-inject the...
Definition IdtEmulation.c:475
UCHAR VmxVmread32P(size_t Field, UINT32 *FieldValue)
VMX VMREAD instruction (32-bit, pointer variant).
Definition PlatformIntrinsicsVmx.c:227
UCHAR BOOLEAN
Definition BasicTypes.h:35
#define TRUE
Definition BasicTypes.h:114
#define FALSE
Definition BasicTypes.h:113
#define LogError(format,...)
Log in the case of error.
Definition HyperDbgHyperLogIntrinsics.h:113
@ INTERRUPT_TYPE_EXTERNAL_INTERRUPT
Definition Events.h:50

◆ IdtEmulationhandleHostInterrupt()

VOID IdtEmulationhandleHostInterrupt ( _Inout_ INTERRUPT_TRAP_FRAME * IntrTrapFrame)

Handle Page-fault exception bitmap VM-exits.

Parameters
VCpuThe virtual processor's state
InterruptExitinterrupt exit information
Returns
VOID
190{
191 UINT64 PageFaultCr2;
192 ULONG CurrentCore;
193 BOOLEAN Interruptible;
194 VMX_INTERRUPTIBILITY_STATE InterruptibilityState = {0};
195 CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
196 VIRTUAL_MACHINE_STATE * VCpu = &g_GuestState[CurrentCore];
197
198 //
199 // Store the latest exception vector
200 //
201 VCpu->LastExceptionOccurredInHost = IntrTrapFrame->vector;
202
203 switch (IntrTrapFrame->vector)
204 {
206
207 //
208 // host NMIs
209 //
210 // LogInfo("NMI received!");
211
212 //
213 // Check if NMI needs to be injected back to the guest or not
214 // Trap frame is sent because as this function unreference this
215 // parameter, NULL cannot be sent
216 //
217 if (!VmxBroadcastHandleNmiCallback((PVOID)IntrTrapFrame, FALSE))
218 {
219 //
220 // We cannot just use the NMI Window Exiting here because
221 // in certain scenarios, VMRESUME with Error 0x7 will happen
222 // Which means that the layout of the VMCS is wrong
223 //
224 // For the future reference, I think using NMI Windows Exiting
225 // here is also not useful but in theory it should serve as a
226 // backup plan if the system is not ready to receive NMIs, then
227 // we could inject it when the NMI Window is open but in reality
228 // it will corrupt the VMCS layout (VMRESUME 0x7 error)
229 //
230
231 //
232 // Check if interruptibility state allows NMIs or not
233 //
234 VmxVmread32P(VMCS_GUEST_INTERRUPTIBILITY_STATE, &InterruptibilityState.AsUInt);
235
236 Interruptible = !InterruptibilityState.BlockingByNmi;
237
238 if (Interruptible)
239 {
240 //
241 // Re-inject the NMI
242 //
243 EventInjectNmi(VCpu);
244 }
245 else
246 {
247 //
248 // Inject NMI when the NMI Window opened
249 //
251 }
252 }
253
254 break;
255
257
258 //
259 // host page-fault
260 //
261 PageFaultCr2 = CpuReadCr2();
262
263 LogInfo("Page-fault received, rip: %llx, rsp: %llx, error: %llx, CR2: %llx",
264 IntrTrapFrame->rip,
265 IntrTrapFrame->rsp,
266 IntrTrapFrame->error,
267 PageFaultCr2);
268
269 break;
270
271 default:
272
273 //
274 // host exceptions
275 //
276 LogInfo("Host exception, rip: %llx, rsp: %llx, error: %llx, vector: %x",
277 IntrTrapFrame->rip,
278 IntrTrapFrame->rsp,
279 IntrTrapFrame->error,
280 IntrTrapFrame->vector);
281 DbgBreakPoint();
282
283 break;
284 }
285}
VOID EventInjectNmi(VIRTUAL_MACHINE_STATE *VCpu)
Inject NMI to the guest (Event Injection).
Definition Events.c:96
VOID HvSetNmiWindowExiting(BOOLEAN Set)
Set NMI-window exiting.
Definition Hv.c:758
ULONG_PTR CpuReadCr2(VOID)
Read CR2.
Definition PlatformIntrinsics.c:64
BOOLEAN VmxBroadcastHandleNmiCallback(PVOID Context, BOOLEAN Handled)
Handles NMIs in kernel-mode.
Definition VmxBroadcast.c:92
void * PVOID
Definition BasicTypes.h:56
unsigned long ULONG
Definition BasicTypes.h:31
#define LogInfo(format,...)
Define log variables.
Definition HyperDbgHyperLogIntrinsics.h:71
struct _VIRTUAL_MACHINE_STATE VIRTUAL_MACHINE_STATE
The status of each core after and before VMX.
VIRTUAL_MACHINE_STATE * g_GuestState
Save the state and variables related to virtualization on each to logical core.
Definition GlobalVariables.h:38
UINT8 LastExceptionOccurredInHost
Definition State.h:354

◆ IdtEmulationHandleInterruptWindowExiting()

VOID IdtEmulationHandleInterruptWindowExiting ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu)

Handle interrupt-window exitings.

Parameters
VCpuThe virtual processor's state
Returns
VOID
663{
664 VMEXIT_INTERRUPT_INFORMATION InterruptExit = {0};
665 BOOLEAN InjectPageFault = FALSE;
666
667 //
668 // Check if page-fault needs to be injected or not
669 //
671 {
673 }
674
675 //
676 // Check if another interrupt (page-fault) needed to injected or not
677 //
678 if (!InjectPageFault)
679 {
680 for (SIZE_T i = 0; i < PENDING_INTERRUPTS_BUFFER_CAPACITY; i++)
681 {
682 //
683 // Find an empty space
684 //
685 if (VCpu->PendingExternalInterrupts[i] != NULL_ZERO)
686 {
687 //
688 // Save it for re-injection (interrupt-window exiting)
689 //
690 InterruptExit.AsUInt = VCpu->PendingExternalInterrupts[i];
691
692 //
693 // Free the entry
694 //
695 VCpu->PendingExternalInterrupts[i] = NULL_ZERO;
696 break;
697 }
698 }
699
700 if (InterruptExit.AsUInt == 0)
701 {
702 //
703 // Nothing left in pending state, let's disable the interrupt window exiting
704 //
706 }
707 else
708 {
709 //
710 // Inject the interrupt/exception
711 //
712
713 EventInjectInterruptOrException(InterruptExit);
714 }
715 }
716
717 //
718 // avoid incrementing rip
719 //
721}
BOOLEAN IdtEmulationInjectPageFaultWhenInterruptWindowsIsOpen(_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
Injects a page-fault when interrupt window is open.
Definition IdtEmulation.c:625
#define PENDING_INTERRUPTS_BUFFER_CAPACITY
Pending External Interrupts Buffer Capacity.
Definition State.h:33
BOOLEAN g_WaitingForInterruptWindowToInjectPageFault
Shows whether the VMM is waiting to inject a page-fault or not.
Definition GlobalVariables.h:192

◆ IdtEmulationHandleNmiWindowExiting()

VOID IdtEmulationHandleNmiWindowExiting ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu)

Handle NMI-window exitings.

Parameters
VCpuThe virtual processor's state
Returns
VOID
606{
607 //
608 // Inject the NMI into the guest
609 //
610 EventInjectNmi(VCpu);
611
612 //
613 // Disable NMI-window exiting since we have no more NMIs to inject
614 //
616}

◆ IdtEmulationHandlePageFaults()

VOID IdtEmulationHandlePageFaults ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu,
_In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit )

Handle Page-fault exception bitmap VM-exits.

Parameters
VCpuThe virtual processor's state
InterruptExitinterrupt exit information
Returns
VOID
298{
299 UINT32 ErrorCode = 0;
300 PAGE_FAULT_EXCEPTION PageFaultErrorCode = {0};
301 UINT64 PageFaultAddress = 0;
302
303 //
304 // Read the error code and exiting address
305 //
306 VmxVmread32P(VMCS_VMEXIT_INTERRUPTION_ERROR_CODE, &ErrorCode);
307 PageFaultErrorCode.AsUInt = ErrorCode;
308
309 //
310 // Read the page-fault address
311 //
312 VmxVmread64P(VMCS_EXIT_QUALIFICATION, &PageFaultAddress);
313
314 // LogInfo("#PF Fault = %016llx, Page Fault Code = 0x%x | %s%s%s%s",
315 // PageFaultAddress,
316 // PageFaultErrorCode.AsUInt,
317 // PageFaultErrorCode.Present ? "p" : "",
318 // PageFaultErrorCode.Write ? "w" : "",
319 // PageFaultErrorCode.UserModeAccess ? "u" : "",
320 // PageFaultErrorCode.Execute ? "f" : "");
321
322 //
323 // Handle page-faults
324 //
325 EventInjectPageFaults(VCpu, InterruptExit, PageFaultAddress, PageFaultErrorCode);
326}
VOID EventInjectPageFaults(_Inout_ VIRTUAL_MACHINE_STATE *VCpu, _In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit, _In_ UINT64 PageFaultAddress, _In_ PAGE_FAULT_EXCEPTION PageFaultCode)
inject PFs to the guest
Definition Events.c:192
unsigned int UINT32
Definition BasicTypes.h:54

◆ IdtEmulationInjectInterruptWhenInterruptWindowIsOpen()

BOOLEAN IdtEmulationInjectInterruptWhenInterruptWindowIsOpen ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu,
_In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit )

if the guest is not interruptible, then we save the details of each interrupt so we can re-inject them to the guest whenever the interrupt window is open

Parameters
VCpuThe virtual processor's state
InterruptExitinterrupt info from vm-exit
Returns
BOOLEAN
477{
478 BOOLEAN FoundAPlaceForFutureInjection = FALSE;
479
480 //
481 // We can't inject interrupt because the guest's state is not interruptible
482 // we have to queue it an re-inject it when the interrupt window is opened !
483 //
484 for (SIZE_T i = 0; i < PENDING_INTERRUPTS_BUFFER_CAPACITY; i++)
485 {
486 //
487 // Find an empty space
488 //
489 if (VCpu->PendingExternalInterrupts[i] == NULL_ZERO)
490 {
491 //
492 // Save it for future re-injection (interrupt-window exiting)
493 //
494 VCpu->PendingExternalInterrupts[i] = InterruptExit.AsUInt;
495 FoundAPlaceForFutureInjection = TRUE;
496 break;
497 }
498 }
499
500 return FoundAPlaceForFutureInjection;
501}

◆ IdtEmulationInjectPageFaultWhenInterruptWindowsIsOpen()

BOOLEAN IdtEmulationInjectPageFaultWhenInterruptWindowsIsOpen ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu)

Injects a page-fault when interrupt window is open.

Parameters
VCpuThe virtual processor's state
Returns
BOOLEAN
626{
627 //
628 // Check if all the injections are done or not
629 //
631 {
633 return FALSE;
634 }
635
636 //
637 // Inject the page-fault (by cr2)
638 //
642
644 {
646 }
647 else
648 {
650 }
651
652 return TRUE;
653}
#define SIZE_2_MB
Integer 2MB.
Definition Ept.h:31
VOID EventInjectPageFaultWithCr2(VIRTUAL_MACHINE_STATE *VCpu, UINT64 Address, UINT32 PageFaultCode)
Inject page-fault with an address as cr2.
Definition Events.c:281
IMPORT_EXPORT_VMM BOOLEAN MemoryMapperCheckIfPdeIsLargePageOnTargetProcess(_In_ PVOID Va)
UINT64 g_PageFaultInjectionAddressTo
The (to) address for page-fault injection.
Definition GlobalVariables.h:204
UINT64 g_PageFaultInjectionAddressFrom
The (from) address for page-fault injection.
Definition GlobalVariables.h:198
UINT32 g_PageFaultInjectionErrorCode
The error code for page-fault injection.
Definition GlobalVariables.h:210
#define PAGE_SIZE
Size of each page (4096 bytes).
Definition common.h:80

◆ IdtEmulationPrepareHostIdt()

VOID IdtEmulationPrepareHostIdt ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu)

Prepare Host IDT.

Parameters
VCpuThe virtual processor's state
Returns
VOID
118{
119 SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 * VmxHostIdt = (SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 *)VCpu->HostIdt;
120 SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 * WindowsIdt = (SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 *)AsmGetIdtBase();
121
122 //
123 // Zero the memory
124 //
125 RtlZeroMemory(VmxHostIdt, HOST_IDT_DESCRIPTOR_COUNT * sizeof(SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64));
126
127 //
128 // Copy OS interrupt (IDT) entries
129 //
130 RtlCopyBytes(VmxHostIdt,
131 WindowsIdt,
132 HOST_IDT_DESCRIPTOR_COUNT * sizeof(SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64));
133
134 /*
135 for (SIZE_T i = 0; i < HOST_IDT_DESCRIPTOR_COUNT; i++)
136 {
137 SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 CurrentEntry = WindowsIdt[i];
138
139 UINT64 Offset = 0;
140 Offset |= ((UINT64)CurrentEntry.OffsetLow) << 0;
141 Offset |= ((UINT64)CurrentEntry.OffsetMiddle) << 16;
142 Offset |= ((UINT64)CurrentEntry.OffsetHigh) << 32;
143
144 // LogInfo("IDT Entry [%d] at: %llx", i, Offset);
145
146 IdtEmulationCreateInterruptGate((PVOID)Offset, &VmxHostIdt[i]);
147 }
148 */
149
150 //
151 // Function related to handling host IDT are a modified version of the following project:
152 // https://github.com/jonomango/hv/blob/main/hv
153 //
154
155 //
156 // Add customize interrupt handlers
157 //
159 // IdtEmulationCreateInterruptGate((PVOID)InterruptHandler1, &VmxHostIdt[EXCEPTION_VECTOR_DEBUG_BREAKPOINT]); // #DB
161 // IdtEmulationCreateInterruptGate((PVOID)InterruptHandler3, &VmxHostIdt[EXCEPTION_VECTOR_BREAKPOINT]); // #BP
171 // IdtEmulationCreateInterruptGate((PVOID)InterruptHandler14, &VmxHostIdt[EXCEPTION_VECTOR_PAGE_FAULT]); // #PF
178}
VOID IdtEmulationCreateInterruptGate(PVOID Handler, SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 *Entry)
Create an interrupt gate that points to the supplied interrupt handler.
Definition IdtEmulation.c:73
#define HOST_IDT_DESCRIPTOR_COUNT
Maximum number of interrupt entries in IDT.
Definition IdtEmulation.h:29
VOID InterruptHandler17()
The 17th entry in IDT.
VOID InterruptHandler13()
The 13th entry in IDT.
VOID InterruptHandler11()
The 11th entry in IDT.
UINT64 AsmGetIdtBase()
Get IDT base.
VOID InterruptHandler2()
The 2nd entry in IDT.
VOID InterruptHandler12()
The 12th entry in IDT.
VOID InterruptHandler19()
The 19th entry in IDT.
VOID InterruptHandler8()
The 8th entry in IDT.
VOID InterruptHandler18()
The 18th entry in IDT.
VOID InterruptHandler20()
The 20th entry in IDT.
VOID InterruptHandler30()
The 30th entry in IDT.
VOID InterruptHandler7()
The 7th entry in IDT.
VOID InterruptHandler5()
The 5th entry in IDT.
VOID InterruptHandler0()
The 0th entry in IDT.
VOID InterruptHandler10()
The 10th entry in IDT.
VOID InterruptHandler16()
The 16th entry in IDT.
VOID InterruptHandler6()
The 6th entry in IDT.
VOID InterruptHandler4()
The 4th entry in IDT.
@ EXCEPTION_VECTOR_RESERVED11
Definition Events.h:54
@ EXCEPTION_VECTOR_GENERAL_PROTECTION_FAULT
Definition Events.h:37
@ EXCEPTION_VECTOR_MATH_FAULT
Definition Events.h:40
@ EXCEPTION_VECTOR_STACK_SEGMENT_FAULT
Definition Events.h:36
@ EXCEPTION_VECTOR_INVALID_TASK_SEGMENT_SELECTOR
Definition Events.h:34
@ EXCEPTION_VECTOR_DIVIDE_ERROR
Definition Events.h:24
@ EXCEPTION_VECTOR_ALIGNMENT_CHECK
Definition Events.h:41
@ EXCEPTION_VECTOR_MACHINE_CHECK
Definition Events.h:42
@ EXCEPTION_VECTOR_SIMD_FLOATING_POINT_NUMERIC_ERROR
Definition Events.h:43
@ EXCEPTION_VECTOR_NO_MATH_COPROCESSOR
Definition Events.h:31
@ EXCEPTION_VECTOR_VIRTUAL_EXCEPTION
Definition Events.h:44
@ EXCEPTION_VECTOR_BOUND_RANGE_EXCEEDED
Definition Events.h:29
@ EXCEPTION_VECTOR_OVERFLOW
Definition Events.h:28
@ EXCEPTION_VECTOR_SEGMENT_NOT_PRESENT
Definition Events.h:35
@ EXCEPTION_VECTOR_DOUBLE_FAULT
Definition Events.h:32

◆ IdtEmulationQueryIdtEntriesRequest()

VOID IdtEmulationQueryIdtEntriesRequest ( PINTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS IdtQueryRequest,
BOOLEAN ReadFromVmxRoot )

Perform query for IDT entries.

Parameters
IdtQueryRequest
ReadFromVmxRoot
Returns
VOID
25{
26 SIDT_ENTRY IdtrReg;
27 KIDT_ENTRY * IdtEntries;
28
29 //
30 // Read IDTR register
31 //
32
33 if (!ReadFromVmxRoot)
34 {
35 //
36 // Since it's not in VMX Root, we can directly read the IDTR register
37 //
38 CpuSidt(&IdtrReg);
39
40 //
41 // Get the IDT base address
42 //
43 IdtEntries = (KIDT_ENTRY *)IdtrReg.IdtBase;
44 }
45 else
46 {
47 //
48 // Since it's in VMX Root, we need to read the IDTR register from the VMCS
49 //
50 IdtEntries = (KIDT_ENTRY *)GetGuestIdtr();
51 }
52
53 //
54 // Gather a list of IDT entries
55 //
56 for (UINT32 i = 0; i < MAX_NUMBER_OF_IDT_ENTRIES; i++)
57 {
58 IdtQueryRequest->IdtEntry[i] = (UINT64)((UINT64)IdtEntries[i].HighestPart << 32) |
59 ((UINT64)IdtEntries[i].HighPart << 16) |
60 (UINT64)IdtEntries[i].LowPart;
61 }
62}
struct _KIDT_ENTRY KIDT_ENTRY
struct _SIDT_ENTRY SIDT_ENTRY
VOID CpuSidt(VOID *Idtr)
Store Interrupt Descriptor Table Register.
Definition PlatformIntrinsics.c:419
#define MAX_NUMBER_OF_IDT_ENTRIES
Maximum number of IDT entries.
Definition RequestStructures.h:1457
IMPORT_EXPORT_VMM UINT64 GetGuestIdtr()
Get the Guest Idtr.
Definition ManageRegs.c:304
UINT64 IdtEntry[MAX_NUMBER_OF_IDT_ENTRIES]
Definition RequestStructures.h:1466
ULONG LowPart
Definition IdtEmulation.h:45
ULONG HighPart
Definition IdtEmulation.h:54
ULONG_PTR IdtBase
Definition IdtEmulation.h:40