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

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

Go to the source code of this file.

Classes

struct  _INTERRUPT_TRAP_FRAME
 Trap frame for interrupts. More...
 
struct  _HOST_EXCEPTION_INFO
 Filled out when a host exception occurs. More...
 

Macros

#define USE_DEFAULT_OS_IDT_AS_HOST_IDT   FALSE
 Whether the hypervisor should use the default OS's IDT as the host IDT in VMCS or not.
 
#define HOST_IDT_DESCRIPTOR_COUNT   256
 Maximum number of interrupt entries in IDT.
 

Typedefs

typedef struct _INTERRUPT_TRAP_FRAME INTERRUPT_TRAP_FRAME
 Trap frame for interrupts.
 
typedef struct _INTERRUPT_TRAP_FRAMEPINTERRUPT_TRAP_FRAME
 
typedef struct _HOST_EXCEPTION_INFO HOST_EXCEPTION_INFO
 Filled out when a host exception occurs.
 
typedef struct _HOST_EXCEPTION_INFOPHOST_EXCEPTION_INFO
 

Functions

VOID IdtEmulationPrepareHostIdt (_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
 Prepare Host IDT.
 
VOID IdtEmulationHandleExceptionAndNmi (_Inout_ VIRTUAL_MACHINE_STATE *VCpu, _In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit)
 Handle NMI and exception vm-exits.
 
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.
 
VOID IdtEmulationHandleInterruptWindowExiting (_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
 Handle interrupt-window exitings.
 

Detailed Description

Header for 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

Macro Definition Documentation

◆ HOST_IDT_DESCRIPTOR_COUNT

#define HOST_IDT_DESCRIPTOR_COUNT   256

Maximum number of interrupt entries in IDT.

◆ USE_DEFAULT_OS_IDT_AS_HOST_IDT

#define USE_DEFAULT_OS_IDT_AS_HOST_IDT   FALSE

Whether the hypervisor should use the default OS's IDT as the host IDT in VMCS or not.

Typedef Documentation

◆ HOST_EXCEPTION_INFO

Filled out when a host exception occurs.

◆ INTERRUPT_TRAP_FRAME

Trap frame for interrupts.

◆ PHOST_EXCEPTION_INFO

◆ PINTERRUPT_TRAP_FRAME

Function Documentation

◆ 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
259{
260 //
261 // Exception or non-maskable interrupt (NMI). Either:
262 // 1: Guest software caused an exception and the bit in the exception bitmap associated with exception's vector was set to 1
263 // 2: An NMI was delivered to the logical processor and the "NMI exiting" VM-execution control was 1.
264 //
265 // VMCS_VMEXIT_INTERRUPTION_INFORMATION shows the exit information about event that occurred and causes this exit
266 // Don't forget to read VMCS_VMEXIT_INTERRUPTION_ERROR_CODE in the case of re-injectiong event
267 //
268
269 switch (InterruptExit.Vector)
270 {
272
273 //
274 // Handle software breakpoints
275 //
276 {
277 UINT64 GuestRip = NULL64_ZERO;
278 BYTE TargetMem = NULL_ZERO;
279
280 __vmx_vmread(VMCS_GUEST_RIP, &GuestRip);
281 MemoryMapperReadMemorySafe(GuestRip, &TargetMem, sizeof(BYTE));
282 if (!EptCheckAndHandleBreakpoint(VCpu) || TargetMem == 0xcc)
283 {
285 {
286 //
287 // Don't increment rip
288 //
290
291 //
292 // Kernel debugger (debugger-mode) is not attached, re-inject the breakpoint
293 //
295 }
296 }
297 }
298
299 break;
300
302
303 //
304 // Handle the #UD, checking if this exception was intentional.
305 //
306 if (!SyscallHookHandleUD(VCpu))
307 {
308 //
309 // If this #UD was found to be unintentional, inject a #UD interruption into the guest.
310 //
312 }
313
314 break;
315
317
318 //
319 // Handle page-faults (#PFs)
320 //
321 IdtEmulationHandlePageFaults(VCpu, InterruptExit);
322
323 break;
324
326
328 {
329 //
330 // It's not because of thread change detection, so re-inject it
331 //
332 EventInjectInterruptOrException(InterruptExit);
333 }
334
335 break;
336
338
339 if (VCpu->EnableExternalInterruptsOnContinue ||
340 VCpu->EnableExternalInterruptsOnContinueMtf ||
341 VCpu->RegisterBreakOnMtf)
342 {
343 //
344 // Ignore the nmi
345 //
346 }
347 else
348 {
349 //
350 // Re-inject the interrupt/exception because it doesn't relate to us
351 //
352 EventInjectInterruptOrException(InterruptExit);
353 }
354
355 break;
356
357 default:
358
359 //
360 // Re-inject the interrupt/exception, nothing special to handle
361 //
362 EventInjectInterruptOrException(InterruptExit);
363
364 break;
365 }
366}
#define NULL_ZERO
Definition BasicTypes.h:51
unsigned char BYTE
Definition BasicTypes.h:24
#define NULL64_ZERO
Definition BasicTypes.h:52
unsigned __int64 UINT64
Definition BasicTypes.h:21
BOOLEAN DebuggingCallbackHandleDebugBreakpointException(UINT32 CoreId)
routine callback to handle debug breakpoint exception
Definition Callback.c:360
BOOLEAN DebuggingCallbackHandleBreakpointException(UINT32 CoreId)
routine callback to handle breakpoint exception
Definition Callback.c:339
_Use_decl_annotations_ BOOLEAN SyscallHookHandleUD(VIRTUAL_MACHINE_STATE *VCpu)
Detect whether the #UD was because of Syscall or Sysret or not.
Definition EferHook.c:228
BOOLEAN EptCheckAndHandleBreakpoint(VIRTUAL_MACHINE_STATE *VCpu)
Check if the breakpoint vm-exit relates to EPT hook or not.
Definition Ept.c:1211
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:324
VOID IdtEmulationHandlePageFaults(_Inout_ VIRTUAL_MACHINE_STATE *VCpu, _In_ VMEXIT_INTERRUPT_INFORMATION InterruptExit)
Handle Page-fault exception bitmap VM-exits.
Definition IdtEmulation.c:209
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafe(UINT64 VaAddressToRead, PVOID BufferToSaveMemory, SIZE_T SizeToRead)
Read memory safely by mapping the buffer (It's a wrapper)
Definition MemoryMapper.c:1101
@ 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

◆ 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
417{
418 BOOLEAN Interruptible = TRUE;
419 VMX_INTERRUPTIBILITY_STATE InterruptibilityState = {0};
420 RFLAGS GuestRflags = {0};
421
422 //
423 // In order to enable External Interrupt Exiting we have to set
424 // PIN_BASED_VM_EXECUTION_CONTROLS_EXTERNAL_INTERRUPT in vmx
425 // pin-based controls (PIN_BASED_VM_EXEC_CONTROL) and also
426 // we should enable VM_EXIT_ACK_INTR_ON_EXIT on vmx vm-exit
427 // controls (VMCS_CTRL_VMEXIT_CONTROLS), also this function might not
428 // always be successful if the guest is not in the interruptible
429 // state so it wait for and interrupt-window exiting to re-inject
430 // the interrupt into the guest
431 //
432 if (VCpu->EnableExternalInterruptsOnContinue ||
433 VCpu->EnableExternalInterruptsOnContinueMtf)
434 {
435 //
436 // Ignore the interrupt as it's suppressed because of instrumentation step-in
437 //
438
439 //
440 // During developing HyperDbg, we realized that if we just ignore the interrupts completely
441 // while we are waiting on 'i' instrumentation step-in command, then the serial device becomes
442 // unresponsive, to solve this issue we hold the details of interrupts so we can re-inject
443 // and process them when we decide to continue the debuggee (guest interrupt windows is open)
444 // this way, the serial device works normally and won't become unresponsive
445 //
447
448 //
449 // avoid incrementing rip
450 //
452 }
453
454 else if (InterruptExit.Valid && InterruptExit.InterruptionType == INTERRUPT_TYPE_EXTERNAL_INTERRUPT)
455 {
456 VmxVmread64P(VMCS_GUEST_RFLAGS, &GuestRflags.AsUInt);
457 VmxVmread32P(VMCS_GUEST_INTERRUPTIBILITY_STATE, &InterruptibilityState.AsUInt);
458
459 //
460 // External interrupts cannot be injected into the
461 // guest if guest isn't interruptible (e.g.: guest
462 // is blocked by "mov ss", or EFLAGS.IF == 0).
463 //
464 Interruptible = GuestRflags.InterruptEnableFlag && !InterruptibilityState.BlockingByMovSs;
465
466 if (Interruptible)
467 {
468 //
469 // Re-inject the interrupt/exception
470 //
471 EventInjectInterruptOrException(InterruptExit);
472 }
473 else
474 {
475 //
476 // We can't inject interrupt because the guest's state is not interruptible
477 // we have to queue it an re-inject it when the interrupt window is opened!
478 //
480
481 //
482 // Enable Interrupt-window exiting.
483 //
485 }
486
487 //
488 // avoid incrementing rip
489 //
491 }
492 else
493 {
494 Interruptible = FALSE;
495
496 LogError("Err, why we are here? it's a vm-exit due to the external"
497 "interrupt and its type is not external interrupt? weird!");
498 }
499}
UCHAR BOOLEAN
Definition BasicTypes.h:39
#define TRUE
Definition BasicTypes.h:55
#define FALSE
Definition BasicTypes.h:54
VOID HvSetInterruptWindowExiting(BOOLEAN Set)
Set Interrupt-window exiting.
Definition Hv.c:606
#define LogError(format,...)
Log in the case of error.
Definition HyperDbgHyperLogIntrinsics.h:113
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:378
UCHAR VmxVmread64P(size_t Field, UINT64 *FieldValue)
VMX VMREAD instruction (64-bit)
Definition Vmx.c:72
UCHAR VmxVmread32P(size_t Field, UINT32 *FieldValue)
VMX VMREAD instruction (32-bit)
Definition Vmx.c:86
@ INTERRUPT_TYPE_EXTERNAL_INTERRUPT
Definition Events.h:50

◆ IdtEmulationHandleInterruptWindowExiting()

VOID IdtEmulationHandleInterruptWindowExiting ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu)

Handle interrupt-window exitings.

Parameters
VCpuThe virtual processor's state
Returns
VOID
566{
567 VMEXIT_INTERRUPT_INFORMATION InterruptExit = {0};
568 BOOLEAN InjectPageFault = FALSE;
569
570 //
571 // Check if page-fault needs to be injected or not
572 //
574 {
576 }
577
578 //
579 // Check if another interrupt (page-fault) needed to injected or not
580 //
581 if (!InjectPageFault)
582 {
583 for (size_t i = 0; i < PENDING_INTERRUPTS_BUFFER_CAPACITY; i++)
584 {
585 //
586 // Find an empty space
587 //
588 if (VCpu->PendingExternalInterrupts[i] != NULL_ZERO)
589 {
590 //
591 // Save it for re-injection (interrupt-window exiting)
592 //
593 InterruptExit.AsUInt = VCpu->PendingExternalInterrupts[i];
594
595 //
596 // Free the entry
597 //
598 VCpu->PendingExternalInterrupts[i] = NULL_ZERO;
599 break;
600 }
601 }
602
603 if (InterruptExit.AsUInt == 0)
604 {
605 //
606 // Nothing left in pending state, let's disable the interrupt window exiting
607 //
609 }
610 else
611 {
612 //
613 // Inject the interrupt/exception
614 //
615
616 EventInjectInterruptOrException(InterruptExit);
617 }
618 }
619
620 //
621 // avoid incrementing rip
622 //
624}
BOOLEAN g_WaitingForInterruptWindowToInjectPageFault
Shows whether the the VMM is waiting to inject a page-fault or not.
Definition GlobalVariables.h:179
BOOLEAN IdtEmulationInjectPageFaultWhenInterruptWindowsIsOpen(_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
Injects a page-fault when interrupt window is open.
Definition IdtEmulation.c:528
#define PENDING_INTERRUPTS_BUFFER_CAPACITY
Pending External Interrupts Buffer Capacity.
Definition State.h:32

◆ IdtEmulationHandleNmiWindowExiting()

VOID IdtEmulationHandleNmiWindowExiting ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu)

Handle NMI-window exitings.

Parameters
VCpuThe virtual processor's state
Returns
VOID
509{
510 //
511 // Inject the NMI into the guest
512 //
513 EventInjectNmi(VCpu);
514
515 //
516 // Disable NMI-window exiting since we have no more NMIs to inject
517 //
519}
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:714

◆ IdtEmulationPrepareHostIdt()

VOID IdtEmulationPrepareHostIdt ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu)

Prepare Host IDT.

Parameters
VCpuThe virtual processor's state
Returns
VOID
68{
69 SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 * VmxHostIdt = (SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 *)VCpu->HostIdt;
70 SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 * WindowsIdt = (SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 *)AsmGetIdtBase();
71
72 //
73 // Zero the memory
74 //
75 RtlZeroMemory(VmxHostIdt, HOST_IDT_DESCRIPTOR_COUNT * sizeof(SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64));
76
77 //
78 // Copy OS interrupt (IDT) entries
79 //
80 RtlCopyBytes(VmxHostIdt,
81 WindowsIdt,
82 HOST_IDT_DESCRIPTOR_COUNT * sizeof(SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64));
83
84 /*
85 for (size_t i = 0; i < HOST_IDT_DESCRIPTOR_COUNT; i++)
86 {
87 SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 CurrentEntry = WindowsIdt[i];
88
89 UINT64 Offset = 0;
90 Offset |= ((UINT64)CurrentEntry.OffsetLow) << 0;
91 Offset |= ((UINT64)CurrentEntry.OffsetMiddle) << 16;
92 Offset |= ((UINT64)CurrentEntry.OffsetHigh) << 32;
93
94 // LogInfo("IDT Entry [%d] at: %llx", i, Offset);
95
96 IdtEmulationCreateInterruptGate((PVOID)Offset, &VmxHostIdt[i]);
97 }
98 */
99
100 //
101 // Function related to handling host IDT are a modified version of the following project:
102 // https://github.com/jonomango/hv/blob/main/hv
103 //
104
105 //
106 // Add customize interrupt handlers
107 //
109 // IdtEmulationCreateInterruptGate((PVOID)InterruptHandler1, &VmxHostIdt[1]); // #DB
111 // IdtEmulationCreateInterruptGate((PVOID)InterruptHandler3, &VmxHostIdt[3]); // #BP
121 IdtEmulationCreateInterruptGate((PVOID)InterruptHandler14, &VmxHostIdt[14]); // #PF
128}
VOID IdtEmulationCreateInterruptGate(PVOID Handler, SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 *Entry)
Create an interrupt gate that points to the supplied interrupt handler.
Definition IdtEmulation.c:23
#define HOST_IDT_DESCRIPTOR_COUNT
Maximum number of interrupt entries in IDT.
Definition IdtEmulation.h:29
void InterruptHandler11()
The 11th entry in IDT.
void InterruptHandler7()
The 7th entry in IDT.
void InterruptHandler8()
The 8th entry in IDT.
void InterruptHandler13()
The 13th entry in IDT.
unsigned long long AsmGetIdtBase()
Get IDT base.
void InterruptHandler14()
The 14th entry in IDT.
void InterruptHandler4()
The 4th entry in IDT.
void InterruptHandler30()
The 30th entry in IDT.
void InterruptHandler5()
The 5th entry in IDT.
void InterruptHandler0()
The 0th entry in IDT.
void InterruptHandler18()
The 18th entry in IDT.
void InterruptHandler20()
The 20th entry in IDT.
void InterruptHandler16()
The 16th entry in IDT.
void InterruptHandler10()
The 10th entry in IDT.
void InterruptHandler6()
The 6th entry in IDT.
void InterruptHandler19()
The 19th entry in IDT.
void InterruptHandler2()
The 2nd entry in IDT.
void InterruptHandler17()
The 17th entry in IDT.
void InterruptHandler12()
The 12th entry in IDT.