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

VMX Instructions and VMX Related Functions. More...

#include "pch.h"

Functions

BOOLEAN VmxCheckVmxSupport ()
 Check whether VMX Feature is supported or not.
BOOLEAN VmxGetCurrentExecutionMode ()
 Check current execution mode (vmx-root and non-root).
BOOLEAN VmxGetCurrentLaunchState ()
 Check if the VMX is launched or not.
BOOLEAN VmxInitialize ()
 Initialize the VMX operation.
BOOLEAN VmxPerformVirtualizationOnAllCores ()
 Initialize essential VMX Operation tasks.
BOOLEAN VmxPerformVirtualizationOnSpecificCore ()
 Allocates Vmx regions for all logical cores (Vmxon region and Vmcs region).
VOID VmxFixCr4AndCr0Bits ()
 Fix values for cr0 and cr4 bits.
BOOLEAN VmxCheckIsOnVmxRoot ()
 It can deterministically check whether the caller is on vmx-root mode or not.
BOOLEAN VmxVirtualizeCurrentSystem (PVOID GuestStack)
 Initialize VMX Operation.
BOOLEAN VmxTerminate ()
 Broadcast to terminate VMX on all logical cores.
VOID VmxPerformVmptrst ()
 Implementation of VMPTRST instruction.
_Use_decl_annotations_ BOOLEAN VmxClearVmcsState (VIRTUAL_MACHINE_STATE *VCpu)
 Clearing Vmcs status using vmclear instruction.
_Use_decl_annotations_ BOOLEAN VmxLoadVmcs (VIRTUAL_MACHINE_STATE *VCpu)
 Implementation of VMPTRLD instruction.
_Use_decl_annotations_ BOOLEAN VmxSetupVmcs (VIRTUAL_MACHINE_STATE *VCpu, PVOID GuestStack)
 Create and Configure a Vmcs Layout.
VOID VmxPerformVmresume ()
 Resume VM using the VMRESUME instruction.
UINT64 VmxVmfunc (UINT32 EptpIndex, UINT32 Function)
 VMFUNC instruction.
VOID VmxPerformVmxoff (VIRTUAL_MACHINE_STATE *VCpu)
 Prepare and execute Vmxoff instruction.
UINT64 VmxReturnStackPointerForVmxoff ()
 Get the RIP of guest (VMCS_GUEST_RIP) in the case of return from VMXOFF.
UINT64 VmxReturnInstructionPointerForVmxoff ()
 Get the RIP of guest (VMCS_GUEST_RIP) in the case of return from VMXOFF.
VOID VmxPerformTermination ()
 Terminate Vmx on all logical cores.
UINT32 VmxCompatibleStrlen (const CHAR *S)
 implementation of vmx-root mode compatible strlen
UINT32 VmxCompatibleWcslen (const WCHAR *S)
 implementation of vmx-root mode compatible wcslen
VOID VmxCompatibleMicroSleep (UINT64 Us)
 VMX-root compatible micro sleep.
INT32 VmxCompatibleStrcmp (const CHAR *Address1, const CHAR *Address2, SIZE_T Num, BOOLEAN IsStrncmp)
 implementation of vmx-root mode compatible strcmp and strncmp
INT32 VmxCompatibleWcscmp (const WCHAR *Address1, const WCHAR *Address2, SIZE_T Num, BOOLEAN IsWcsncmp)
 implementation of vmx-root mode compatible wcscmp and wcsncmp
INT32 VmxCompatibleMemcmp (const CHAR *Address1, const CHAR *Address2, SIZE_T Count)
 implementation of vmx-root mode compatible memcmp
BOOLEAN VmxIsTopLevelHypervisorHyperV ()
 checks if the current top level hypervisor is Hyper-V

Detailed Description

VMX Instructions and VMX Related Functions.

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

Function Documentation

◆ VmxCheckIsOnVmxRoot()

BOOLEAN VmxCheckIsOnVmxRoot ( )

It can deterministically check whether the caller is on vmx-root mode or not.

Returns
BOOLEAN Returns true if current operation mode is vmx-root and false if current operation mode is vmx non-root
439{
440 UINT64 VmcsLink = 0;
441
442 __try
443 {
444 if (!VmxVmread64P(VMCS_GUEST_VMCS_LINK_POINTER, &VmcsLink))
445 {
446 if (VmcsLink != 0)
447 {
448 return TRUE;
449 }
450 }
451 }
452 __except (1)
453 {
454 }
455
456 return FALSE;
457}
UCHAR VmxVmread64P(size_t Field, UINT64 *FieldValue)
VMX VMREAD instruction (64-bit, pointer variant).
Definition PlatformIntrinsicsVmx.c:207
#define TRUE
Definition BasicTypes.h:114
#define FALSE
Definition BasicTypes.h:113

◆ VmxCheckVmxSupport()

BOOLEAN VmxCheckVmxSupport ( )

Check whether VMX Feature is supported or not.

Returns
BOOLEAN Returns true if vmx is supported or false if it's not supported
21{
22 CPUID Data = {0};
23 IA32_FEATURE_CONTROL_REGISTER FeatureControlMsr = {0};
24
25 //
26 // Gets Processor Info and Feature Bits
27 //
28 CpuCpuId((INT *)&Data, 1);
29
30 //
31 // Check For VMX Bit CPUID.ECX[5]
32 //
33 if (!_bittest((const LONG *)&Data.ecx, 5))
34 {
35 //
36 // returns FALSE if vmx is not supported
37 //
38 return FALSE;
39 }
40
41 FeatureControlMsr.AsUInt = CpuReadMsr(IA32_FEATURE_CONTROL);
42
43 //
44 // Commented because of https://stackoverflow.com/questions/34900224/
45 // and https://github.com/HyperDbg/HyperDbg/issues/24
46 // the problem is when writing to IA32_FEATURE_CONTROL MSR, the lock bit
47 // of this MSR Is not set to 0 on most computers, if the user enabled VT-X
48 // from the BIOS the VMXON will be already set so checking lock bit and
49 // then writing to EnableVmxon again is not meaningful since its already
50 // there
51 //
52
53 //
54 // if (FeatureControlMsr.Fields.Lock == 0)
55 // {
56 // FeatureControlMsr.Fields.Lock = TRUE;
57 // FeatureControlMsr.Fields.EnableVmxon = TRUE;
58 // CpuWriteMsr(IA32_FEATURE_CONTROL, FeatureControlMsr.Flags);
59 // }
60
61 if (FeatureControlMsr.EnableVmxOutsideSmx == FALSE)
62 {
63 LogError("Err, you should enable vt-x from BIOS");
64 return FALSE;
65 }
66
67 return TRUE;
68}
VOID CpuCpuId(INT32 *CpuInfo, INT32 FunctionId)
Execute CPUID.
Definition PlatformIntrinsics.c:255
UINT64 CpuReadMsr(ULONG MsrAddress)
Read an MSR.
Definition PlatformIntrinsics.c:213
long LONG
Definition BasicTypes.h:28
int INT
Definition BasicTypes.h:43
#define LogError(format,...)
Log in the case of error.
Definition HyperDbgHyperLogIntrinsics.h:113
struct _CPUID CPUID
CPUID Registers.
Start of Optional Data
Definition script_buffer.hex.txt:8

◆ VmxClearVmcsState()

_Use_decl_annotations_ BOOLEAN VmxClearVmcsState ( VIRTUAL_MACHINE_STATE * VCpu)

Clearing Vmcs status using vmclear instruction.

Parameters
VCpu
Returns
BOOLEAN If vmclear execution was successful it returns true otherwise and if there was error with vmclear then it returns false
629{
630 UINT8 VmclearStatus;
631
632 //
633 // Clear the state of the VMCS to inactive
634 //
635 VmclearStatus = VmxVmclear(&VCpu->VmcsRegionPhysicalAddress);
636
637 LogDebugInfo("VMCS VMCLEAR status : 0x%x", VmclearStatus);
638
639 if (VmclearStatus)
640 {
641 //
642 // Otherwise terminate the VMX
643 //
644 LogDebugInfo("VMCS failed to clear, status : 0x%x", VmclearStatus);
645 VmxVmxoff();
646
647 return FALSE;
648 }
649 return TRUE;
650}
VOID VmxVmxoff(VOID)
VMX VMXOFF instruction.
Definition PlatformIntrinsicsVmx.c:373
UCHAR VmxVmclear(UINT64 *VmcsPhysicalAddress)
VMX VMCLEAR instruction.
Definition PlatformIntrinsicsVmx.c:428
unsigned char UINT8
Definition BasicTypes.h:52
#define LogDebugInfo(format,...)
Log, initialize boot information and debug information.
Definition HyperDbgHyperLogIntrinsics.h:155
UINT64 VmcsRegionPhysicalAddress
Definition State.h:334

◆ VmxCompatibleMemcmp()

INT32 VmxCompatibleMemcmp ( const CHAR * Address1,
const CHAR * Address2,
SIZE_T Count )

implementation of vmx-root mode compatible memcmp

Parameters
Address1
Address2
Count
Returns
INT32 0x2 indicates error, otherwise the same result as memcmp in string.h
1675{
1676 CHAR C1 = NULL_ZERO, C2 = NULL_ZERO;
1677 INT32 Result = 0;
1678 UINT64 AlignedAddress1, AlignedAddress2;
1679 CR3_TYPE GuestCr3;
1680 CR3_TYPE OriginalCr3;
1681
1682 AlignedAddress1 = (UINT64)PAGE_ALIGN((UINT64)Address1);
1683 AlignedAddress2 = (UINT64)PAGE_ALIGN((UINT64)Address2);
1684
1685 //
1686 // Find the current process cr3
1687 //
1689
1690 //
1691 // Move to new cr3
1692 //
1693 OriginalCr3.Flags = CpuReadCr3();
1694 CpuWriteCr3(GuestCr3.Flags);
1695
1696 //
1697 // First check
1698 //
1699 if (!CheckAccessValidityAndSafety(AlignedAddress1, sizeof(WCHAR)) || !CheckAccessValidityAndSafety(AlignedAddress2, sizeof(WCHAR)))
1700 {
1701 //
1702 // Error
1703 //
1704
1705 //
1706 // Move back to original cr3
1707 //
1708 CpuWriteCr3(OriginalCr3.Flags);
1709 return 0x2;
1710 }
1711
1712 while (Count-- > 0 && !Result)
1713 {
1714 /*
1715 C1 = *Address1;
1716 */
1717 MemoryMapperReadMemorySafe((UINT64)Address1, &C1, sizeof(CHAR));
1718
1719 /*
1720 C2 = *Address2;
1721 */
1722 MemoryMapperReadMemorySafe((UINT64)Address2, &C2, sizeof(CHAR));
1723
1724 Address1++;
1725 Address2++;
1726
1727 if (!((UINT64)AlignedAddress1 & (PAGE_SIZE - 1)))
1728 {
1729 if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress1, sizeof(WCHAR)))
1730 {
1731 //
1732 // Error
1733 //
1734
1735 //
1736 // Move back to original cr3
1737 //
1738 CpuWriteCr3(OriginalCr3.Flags);
1739 return 0x2;
1740 }
1741 }
1742
1743 if (!((UINT64)AlignedAddress2 & (PAGE_SIZE - 1)))
1744 {
1745 if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress2, sizeof(WCHAR)))
1746 {
1747 //
1748 // Error
1749 //
1750
1751 //
1752 // Move back to original cr3
1753 //
1754 CpuWriteCr3(OriginalCr3.Flags);
1755 return 0x2;
1756 }
1757 }
1758
1759 Result = C1 - C2;
1760 }
1761
1762 if (Result < 0)
1763 {
1764 Result = -1;
1765 }
1766 else if (Result > 0)
1767 {
1768 Result = 1;
1769 }
1770
1771 //
1772 // Move back to original cr3
1773 //
1774 CpuWriteCr3(OriginalCr3.Flags);
1775 return Result;
1776}
ULONG_PTR CpuReadCr3(VOID)
Read CR3.
Definition PlatformIntrinsics.c:100
VOID CpuWriteCr3(ULONG_PTR Cr3Value)
Write CR3.
Definition PlatformIntrinsics.c:119
signed int INT32
Definition BasicTypes.h:50
#define NULL_ZERO
Definition BasicTypes.h:110
struct _CR3_TYPE CR3_TYPE
CR3 Structure.
char CHAR
Definition BasicTypes.h:33
IMPORT_EXPORT_VMM BOOLEAN CheckAccessValidityAndSafety(UINT64 TargetAddress, UINT32 Size)
Check the safety to access the memory.
Definition AddressCheck.c:318
IMPORT_EXPORT_VMM BOOLEAN MemoryMapperReadMemorySafe(_In_ UINT64 VaAddressToRead, _Inout_ PVOID BufferToSaveMemory, _In_ SIZE_T SizeToRead)
IMPORT_EXPORT_VMM CR3_TYPE LayoutGetCurrentProcessCr3()
Get cr3 of the target running process.
Definition Layout.c:55
#define PAGE_SIZE
Size of each page (4096 bytes).
Definition common.h:80
#define PAGE_ALIGN(Va)
Aligning a page.
Definition common.h:86
UINT64 Flags
Definition BasicTypes.h:239

◆ VmxCompatibleMicroSleep()

VOID VmxCompatibleMicroSleep ( UINT64 Us)

VMX-root compatible micro sleep.

Parameters
UsDelay in micro seconds
Returns
VOID
1372{
1373 LARGE_INTEGER Start, End, Frequency;
1374 KeQueryPerformanceCounter(&Frequency);
1375
1376 LONGLONG Ticks = (Frequency.QuadPart / 1000000) * Us;
1377
1378 Start = KeQueryPerformanceCounter(NULL);
1379
1380 while (TRUE)
1381 {
1382 End = KeQueryPerformanceCounter(NULL);
1383 if (End.QuadPart - Start.QuadPart > Ticks)
1384 break;
1385 }
1386}

◆ VmxCompatibleStrcmp()

INT32 VmxCompatibleStrcmp ( const CHAR * Address1,
const CHAR * Address2,
SIZE_T Num,
BOOLEAN IsStrncmp )

implementation of vmx-root mode compatible strcmp and strncmp

Parameters
Address1
Address2
Numparam IsStrncmp
Returns
INT32 0x2 indicates error, otherwise the same result as strcmp in string.h
1402{
1403 CHAR C1 = NULL_ZERO, C2 = NULL_ZERO;
1404 INT32 Result = 0;
1405 UINT32 Count = 0;
1406 UINT64 AlignedAddress1, AlignedAddress2;
1407 CR3_TYPE GuestCr3;
1408 CR3_TYPE OriginalCr3;
1409
1410 AlignedAddress1 = (UINT64)PAGE_ALIGN((UINT64)Address1);
1411 AlignedAddress2 = (UINT64)PAGE_ALIGN((UINT64)Address2);
1412
1413 //
1414 // Find the current process cr3
1415 //
1417
1418 //
1419 // Move to new cr3
1420 //
1421 OriginalCr3.Flags = CpuReadCr3();
1422 CpuWriteCr3(GuestCr3.Flags);
1423
1424 //
1425 // First check
1426 //
1427 if (!CheckAccessValidityAndSafety(AlignedAddress1, sizeof(CHAR)) || !CheckAccessValidityAndSafety(AlignedAddress2, sizeof(CHAR)))
1428 {
1429 //
1430 // Error
1431 //
1432
1433 //
1434 // Move back to original cr3
1435 //
1436 CpuWriteCr3(OriginalCr3.Flags);
1437 return 0x2;
1438 }
1439
1440 do
1441 {
1442 //
1443 // Check to see if we have byte number constraints
1444 //
1445 if (IsStrncmp)
1446 {
1447 if (Count == Num)
1448 {
1449 //
1450 // Maximum number of bytes reached
1451 //
1452 break;
1453 }
1454 else
1455 {
1456 //
1457 // Maximum number of bytes not reached
1458 //
1459 Count++;
1460 }
1461 }
1462
1463 /*
1464 C1 = *Address1;
1465 */
1466 MemoryMapperReadMemorySafe((UINT64)Address1, &C1, sizeof(CHAR));
1467
1468 /*
1469 C2 = *Address2;
1470 */
1471 MemoryMapperReadMemorySafe((UINT64)Address2, &C2, sizeof(CHAR));
1472
1473 Address1++;
1474 Address2++;
1475
1476 if (!((UINT64)AlignedAddress1 & (PAGE_SIZE - 1)))
1477 {
1478 if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress1, sizeof(CHAR)))
1479 {
1480 //
1481 // Error
1482 //
1483
1484 //
1485 // Move back to original cr3
1486 //
1487 CpuWriteCr3(OriginalCr3.Flags);
1488 return 0x2;
1489 }
1490 }
1491
1492 if (!((UINT64)AlignedAddress2 & (PAGE_SIZE - 1)))
1493 {
1494 if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress2, sizeof(CHAR)))
1495 {
1496 //
1497 // Error
1498 //
1499
1500 //
1501 // Move back to original cr3
1502 //
1503 CpuWriteCr3(OriginalCr3.Flags);
1504 return 0x2;
1505 }
1506 }
1507 Result = C1 - C2;
1508 } while (!Result && C2);
1509
1510 if (Result < 0)
1511 {
1512 Result = -1;
1513 }
1514 else if (Result > 0)
1515 {
1516 Result = 1;
1517 }
1518
1519 //
1520 // Move back to original cr3
1521 //
1522 CpuWriteCr3(OriginalCr3.Flags);
1523 return Result;
1524}
unsigned int UINT32
Definition BasicTypes.h:54
@ Num
Definition commands.h:167

◆ VmxCompatibleStrlen()

UINT32 VmxCompatibleStrlen ( const CHAR * S)

implementation of vmx-root mode compatible strlen

Parameters
S
Returns
UINT32 If 0x0 indicates an error, otherwise length of the string
1193{
1194 CHAR Temp = NULL_ZERO;
1195 UINT32 Count = 0;
1196 UINT64 AlignedAddress;
1197 CR3_TYPE GuestCr3;
1198 CR3_TYPE OriginalCr3;
1199
1200 AlignedAddress = (UINT64)PAGE_ALIGN((UINT64)S);
1201
1202 //
1203 // Find the current process cr3
1204 //
1206
1207 //
1208 // Move to new cr3
1209 //
1210 OriginalCr3.Flags = CpuReadCr3();
1211 CpuWriteCr3(GuestCr3.Flags);
1212
1213 //
1214 // First check
1215 //
1216 if (!CheckAccessValidityAndSafety(AlignedAddress, sizeof(CHAR)))
1217 {
1218 //
1219 // Error
1220 //
1221
1222 //
1223 // Move back to original cr3
1224 //
1225 CpuWriteCr3(OriginalCr3.Flags);
1226 return 0;
1227 }
1228
1229 while (TRUE)
1230 {
1231 /*
1232 Temp = *S;
1233 */
1234 MemoryMapperReadMemorySafe((UINT64)S, &Temp, sizeof(CHAR));
1235
1236 if (Temp != '\0')
1237 {
1238 Count++;
1239 S++;
1240 }
1241 else
1242 {
1243 //
1244 // Move back to original cr3
1245 //
1246 CpuWriteCr3(OriginalCr3.Flags);
1247 return Count;
1248 }
1249
1250 if (!((UINT64)S & (PAGE_SIZE - 1)))
1251 {
1252 if (!CheckAccessValidityAndSafety((UINT64)S, sizeof(CHAR)))
1253 {
1254 //
1255 // Error
1256 //
1257
1258 //
1259 // Move back to original cr3
1260 //
1261 CpuWriteCr3(OriginalCr3.Flags);
1262 return 0;
1263 }
1264 }
1265 }
1266
1267 //
1268 // Move back to original cr3
1269 //
1270 CpuWriteCr3(OriginalCr3.Flags);
1271}
ThreeOpFunc1 interlocked_compare_exchange ThreeOpFunc2 event_inject_error_code memcpy memcpy_pa TwoOpFunc1 ed eb eq interlocked_exchange interlocked_exchange_add eb_pa ed_pa eq_pa TwoOpFunc2 spinlock_lock_custom_wait event_inject OneOpFunc1 poi db dd dw dq neg hi low not check_address disassemble_len disassemble_len32 disassemble_len64 interlocked_increment interlocked_decrement reference physical_to_virtual virtual_to_physical poi_pa hi_pa low_pa db_pa dd_pa dw_pa dq_pa lbr_restore_by_filter OneOpFunc2 print formats event_enable event_disable event_clear test_statement spinlock_lock spinlock_unlock event_sc microsleep OneOpFunc3 strlen TwoOpFunc3 strcmp ThreeOpFunc3 memcmp strncmp ThreeOpFunc4 wcsncmp OneOpFunc4 wcslen TwoOpFunc4 wcscmp ZeroOpFunc1 pause flush event_trace_step event_trace_step_in event_trace_step_out event_trace_instrumentation_step event_trace_instrumentation_step_in ZeroOpFunc2 rdtsc rdtscp lbr_save lbr_dump lbr_print lbr_restore lbr_check VarArgFunc1 printf OperatorsTwoOperand or xor and asr asl add sub mul div mod gt lt egt elt equal neq OperatorsOneOperand inc dec reference AssignmentOperator add_assignment sub_assignment mul_assignment div_assignment mod_assignment asl_assignment asr_assignment and_assignment xor_assignment or_assignment SemantiRules jmp jz jnz mov start_of_do_while start_of_do_while_commands end_of_do_while start_of_for for_inc_dec start_of_for_ommands end_of_if ignore_lvalue push pop call ret Registers rax eax ax ah al rcx ecx cx ch cl rdx edx dx dh dl rbx ebx bx bh bl rsp esp sp spl rbp ebp bp bpl rsi esi si sil rdi edi di dil r8 r8d r8w r8h r8l r9 r9d r9w r9h r9l r10 r10d r10w r10h r10l r11 r11d r11w r11h r11l r12 r12d r12w r12h r12l r13 r13d r13w r13h r13l r14 r14d r14w r14h r14l r15 r15d r15w r15h r15l ds es fs gs cs ss rflags eflags flags cf pf af zf sf tf if df of iopl nt rf vm ac vif vip id rip eip ip idtr ldtr gdtr tr cr0 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr6 dr7 PseudoRegisters pid tid pname core proc thread peb teb ip buffer context event_tag event_id event_stage date time S STATEMENT S S
Definition Grammar.txt:57

◆ VmxCompatibleWcscmp()

INT32 VmxCompatibleWcscmp ( const WCHAR * Address1,
const WCHAR * Address2,
SIZE_T Num,
BOOLEAN IsWcsncmp )

implementation of vmx-root mode compatible wcscmp and wcsncmp

Parameters
Address1
Address2
Num
IsWcsncmp
Returns
INT32 0x2 indicates error, otherwise the same result as wcscmp in string.h
1540{
1541 WCHAR C1 = NULL_ZERO, C2 = NULL_ZERO;
1542 INT32 Result = 0;
1543 UINT32 Count = 0;
1544 UINT64 AlignedAddress1, AlignedAddress2;
1545 CR3_TYPE GuestCr3;
1546 CR3_TYPE OriginalCr3;
1547
1548 AlignedAddress1 = (UINT64)PAGE_ALIGN((UINT64)Address1);
1549 AlignedAddress2 = (UINT64)PAGE_ALIGN((UINT64)Address2);
1550
1551 //
1552 // Find the current process cr3
1553 //
1555
1556 //
1557 // Move to new cr3
1558 //
1559 OriginalCr3.Flags = CpuReadCr3();
1560 CpuWriteCr3(GuestCr3.Flags);
1561
1562 //
1563 // First check
1564 //
1565 if (!CheckAccessValidityAndSafety(AlignedAddress1, sizeof(WCHAR)) || !CheckAccessValidityAndSafety(AlignedAddress2, sizeof(WCHAR)))
1566 {
1567 //
1568 // Error
1569 //
1570
1571 //
1572 // Move back to original cr3
1573 //
1574 CpuWriteCr3(OriginalCr3.Flags);
1575 return 0x2;
1576 }
1577
1578 do
1579 {
1580 //
1581 // Check to see if we have byte number constraints
1582 //
1583 if (IsWcsncmp)
1584 {
1585 if (Count == Num)
1586 {
1587 //
1588 // Maximum number of bytes reached
1589 //
1590 break;
1591 }
1592 else
1593 {
1594 //
1595 // Maximum number of bytes not reached
1596 //
1597 Count++;
1598 }
1599 }
1600
1601 /*
1602 C1 = *Address1;
1603 */
1604 MemoryMapperReadMemorySafe((UINT64)Address1, &C1, sizeof(WCHAR));
1605
1606 /*
1607 C2 = *Address2;
1608 */
1609 MemoryMapperReadMemorySafe((UINT64)Address2, &C2, sizeof(WCHAR));
1610
1611 Address1++;
1612 Address2++;
1613
1614 if (!((UINT64)AlignedAddress1 & (PAGE_SIZE - 1)))
1615 {
1616 if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress1, sizeof(WCHAR)))
1617 {
1618 //
1619 // Error
1620 //
1621
1622 //
1623 // Move back to original cr3
1624 //
1625 CpuWriteCr3(OriginalCr3.Flags);
1626 return 0x2;
1627 }
1628 }
1629
1630 if (!((UINT64)AlignedAddress2 & (PAGE_SIZE - 1)))
1631 {
1632 if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress2, sizeof(WCHAR)))
1633 {
1634 //
1635 // Error
1636 //
1637
1638 //
1639 // Move back to original cr3
1640 //
1641 CpuWriteCr3(OriginalCr3.Flags);
1642 return 0x2;
1643 }
1644 }
1645
1646 Result = C1 - C2;
1647 } while (!Result && C2);
1648
1649 if (Result < 0)
1650 {
1651 Result = -1;
1652 }
1653 else if (Result > 0)
1654 {
1655 Result = 1;
1656 }
1657
1658 //
1659 // Move back to original cr3
1660 //
1661 CpuWriteCr3(OriginalCr3.Flags);
1662 return Result;
1663}

◆ VmxCompatibleWcslen()

UINT32 VmxCompatibleWcslen ( const WCHAR * S)

implementation of vmx-root mode compatible wcslen

Parameters
S
Returns
UINT32 If 0x0 indicates an error, otherwise length of the string
1282{
1283 WCHAR Temp = NULL_ZERO;
1284 UINT32 Count = 0;
1285 UINT64 AlignedAddress;
1286 CR3_TYPE GuestCr3;
1287 CR3_TYPE OriginalCr3;
1288
1289 AlignedAddress = (UINT64)PAGE_ALIGN((UINT64)S);
1290
1291 //
1292 // Find the current process cr3
1293 //
1295
1296 //
1297 // Move to new cr3
1298 //
1299 OriginalCr3.Flags = CpuReadCr3();
1300 CpuWriteCr3(GuestCr3.Flags);
1301
1302 AlignedAddress = (UINT64)PAGE_ALIGN((UINT64)S);
1303
1304 //
1305 // First check
1306 //
1307 if (!CheckAccessValidityAndSafety(AlignedAddress, sizeof(WCHAR)))
1308 {
1309 //
1310 // Error
1311 //
1312
1313 //
1314 // Move back to original cr3
1315 //
1316 CpuWriteCr3(OriginalCr3.Flags);
1317 return 0;
1318 }
1319
1320 while (TRUE)
1321 {
1322 /*
1323 Temp = *S;
1324 */
1325 MemoryMapperReadMemorySafe((UINT64)S, &Temp, sizeof(WCHAR));
1326
1327 if (Temp != '\0\0')
1328 {
1329 Count++;
1330 S++;
1331 }
1332 else
1333 {
1334 //
1335 // Move back to original cr3
1336 //
1337 CpuWriteCr3(OriginalCr3.Flags);
1338 return Count;
1339 }
1340
1341 if (!((UINT64)S & (PAGE_SIZE - 1)))
1342 {
1343 if (!CheckAccessValidityAndSafety((UINT64)S, sizeof(WCHAR)))
1344 {
1345 //
1346 // Error
1347 //
1348
1349 //
1350 // Move back to original cr3
1351 //
1352 CpuWriteCr3(OriginalCr3.Flags);
1353 return 0;
1354 }
1355 }
1356 }
1357
1358 //
1359 // Move back to original cr3
1360 //
1361 CpuWriteCr3(OriginalCr3.Flags);
1362}

◆ VmxFixCr4AndCr0Bits()

VOID VmxFixCr4AndCr0Bits ( )

Fix values for cr0 and cr4 bits.

The Cr4 And Cr0 Bits During VMX Operation Preventing Them From Any Change (https://revers.engineering/day-2-entering-vmx-operation/)

Returns
VOID
404{
405 CR_FIXED CrFixed = {0};
406 CR4 Cr4 = {0};
407 CR0 Cr0 = {0};
408
409 //
410 // Fix Cr0
411 //
412 CrFixed.Flags = CpuReadMsr(IA32_VMX_CR0_FIXED0);
413 Cr0.AsUInt = CpuReadCr0();
414 Cr0.AsUInt |= CrFixed.Fields.Low;
415 CrFixed.Flags = CpuReadMsr(IA32_VMX_CR0_FIXED1);
416 Cr0.AsUInt &= CrFixed.Fields.Low;
417 CpuWriteCr0(Cr0.AsUInt);
418
419 //
420 // Fix Cr4
421 //
422 CrFixed.Flags = CpuReadMsr(IA32_VMX_CR4_FIXED0);
423 Cr4.AsUInt = CpuReadCr4();
424 Cr4.AsUInt |= CrFixed.Fields.Low;
425 CrFixed.Flags = CpuReadMsr(IA32_VMX_CR4_FIXED1);
426 Cr4.AsUInt &= CrFixed.Fields.Low;
427 CpuWriteCr4(Cr4.AsUInt);
428}
VOID CpuWriteCr4(ULONG_PTR Cr4Value)
Write CR4.
Definition PlatformIntrinsics.c:155
ULONG_PTR CpuReadCr4(VOID)
Read CR4.
Definition PlatformIntrinsics.c:136
ULONG_PTR CpuReadCr0(VOID)
Read CR0.
Definition PlatformIntrinsics.c:28
VOID CpuWriteCr0(ULONG_PTR Cr0Value)
Write CR0.
Definition PlatformIntrinsics.c:47
union _CR_FIXED CR_FIXED
UINT64 Flags
Definition Common.h:93
ULONG Low
Definition Common.h:97
struct _CR_FIXED::@007200302366232112033323335144251163245112120214 Fields

◆ VmxGetCurrentExecutionMode()

BOOLEAN VmxGetCurrentExecutionMode ( )

Check current execution mode (vmx-root and non-root).

Returns
BOOLEAN Returns true if the execution is on vmx-root, otherwise false
77{
78 if (g_GuestState)
79 {
80 ULONG CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
81 VIRTUAL_MACHINE_STATE * CurrentVmState = &g_GuestState[CurrentCore];
82
84 }
85 else
86 {
87 //
88 // The structure for guest state is not initialized, thus, we're in VMX non-root
89 //
91 }
92}
unsigned long ULONG
Definition BasicTypes.h:31
@ VmxExecutionModeNonRoot
Definition DataTypes.h:115
@ VmxExecutionModeRoot
Definition DataTypes.h:116
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
BOOLEAN IsOnVmxRootMode
Definition State.h:312

◆ VmxGetCurrentLaunchState()

BOOLEAN VmxGetCurrentLaunchState ( )

Check if the VMX is launched or not.

Returns
BOOLEAN Returns true if it's launched, otherwise false
101{
102 ULONG CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
103 VIRTUAL_MACHINE_STATE * CurrentVmState = &g_GuestState[CurrentCore];
104
105 return CurrentVmState->HasLaunched;
106}
BOOLEAN HasLaunched
Definition State.h:314

◆ VmxInitialize()

BOOLEAN VmxInitialize ( )

Initialize the VMX operation.

Returns
BOOLEAN Returns true if vmx initialized successfully
115{
116 ULONG ProcessorsCount;
117
118 //
119 // ****** Start Virtualizing Current System ******
120 //
121
122 //
123 // Initiating EPTP and VMX
124 //
126 {
127 //
128 // there was error somewhere in initializing
129 //
130 return FALSE;
131 }
132
133 ProcessorsCount = KeQueryActiveProcessorCount(0);
134
135 for (SIZE_T ProcessorID = 0; ProcessorID < ProcessorsCount; ProcessorID++)
136 {
137 //
138 // *** Launching VM for Test (in the all logical processor) ***
139 //
140
141 VIRTUAL_MACHINE_STATE * GuestState = &g_GuestState[ProcessorID];
142
143 //
144 // Allocating VMM Stack
145 //
146 if (!VmxAllocateVmmStack(GuestState))
147 {
148 //
149 // Some error in allocating Vmm Stack
150 //
151 return FALSE;
152 }
153
154 //
155 // Allocating MSR Bit
156 //
157 if (!VmxAllocateMsrBitmap(GuestState))
158 {
159 //
160 // Some error in allocating Msr Bitmaps
161 //
162 return FALSE;
163 }
164
165 //
166 // Allocating I/O Bit
167 //
168 if (!VmxAllocateIoBitmaps(GuestState))
169 {
170 //
171 // Some error in allocating I/O Bitmaps
172 //
173 return FALSE;
174 }
175
176#if USE_DEFAULT_OS_IDT_AS_HOST_IDT == FALSE
177
178 //
179 // Allocating Host IDT
180 //
181 if (!VmxAllocateHostIdt(GuestState))
182 {
183 //
184 // Some error in allocating Host IDT
185 //
186 return FALSE;
187 }
188#endif // USE_DEFAULT_OS_IDT_AS_HOST_IDT == FALSE
189
190#if USE_DEFAULT_OS_GDT_AS_HOST_GDT == FALSE
191
192 //
193 // Allocating Host GDT
194 //
195 if (!VmxAllocateHostGdt(GuestState))
196 {
197 //
198 // Some error in allocating Host GDT
199 //
200 return FALSE;
201 }
202
203 //
204 // Allocating Host TSS
205 //
206 if (!VmxAllocateHostTss(GuestState))
207 {
208 //
209 // Some error in allocating Host TSS
210 //
211 return FALSE;
212 }
213
214#endif // USE_DEFAULT_OS_GDT_AS_HOST_GDT == FALSE
215
216#if USE_INTERRUPT_STACK_TABLE == TRUE
217
218 //
219 // Allocating Host Interrupt Stack
220 //
221 if (!VmxAllocateHostInterruptStack(GuestState))
222 {
223 //
224 // Some error in allocating Interrupt Stack
225 //
226 return FALSE;
227 }
228
229#endif // USE_INTERRUPT_STACK_TABLE == TRUE
230 }
231
232 //
233 // Create a bitmap of the MSRs that cause #GP
234 //
236
237 if (g_MsrBitmapInvalidMsrs == NULL)
238 {
239 return FALSE;
240 }
241
242 //
243 // As we want to support more than 32 processor (64 logical-core)
244 // we let windows execute our routine for us
245 //
246 KeGenericCallDpc(DpcRoutineInitializeGuest, 0x0);
247
248 //
249 // Check if everything is ok then return true otherwise false
250 //
251 if (AsmVmxVmcall(VMCALL_TEST, 0x22, 0x333, 0x4444) == STATUS_SUCCESS)
252 {
253 return TRUE;
254 }
255 else
256 {
257 return FALSE;
258 }
259}
NTSTATUS AsmVmxVmcall(UINT64 VmcallNumber, UINT64 OptionalParam1, UINT64 OptionalParam2, UINT64 OptionalParam3)
Request Vmcall.
#define VMCALL_TEST
VMCALL to test hypervisor.
Definition Vmcall.h:22
BOOLEAN VmxPerformVirtualizationOnAllCores()
Initialize essential VMX Operation tasks.
Definition Vmx.c:267
BOOLEAN VmxAllocateHostIdt(_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
Allocate a buffer for host IDT.
Definition VmxRegions.c:298
UINT64 * VmxAllocateInvalidMsrBimap()
Allocates a buffer and tests for the MSRs that cause GP.
Definition VmxRegions.c:265
BOOLEAN VmxAllocateIoBitmaps(_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
Allocate a buffer for I/O Bitmap.
Definition VmxRegions.c:222
BOOLEAN VmxAllocateMsrBitmap(_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
Allocate a buffer for Msr Bitmap.
Definition VmxRegions.c:193
BOOLEAN VmxAllocateHostInterruptStack(_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
Allocate a buffer for host interrupt stack.
Definition VmxRegions.c:395
BOOLEAN VmxAllocateVmmStack(_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
Allocate VMM Stack.
Definition VmxRegions.c:168
BOOLEAN VmxAllocateHostGdt(_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
Allocate a buffer for host GDT.
Definition VmxRegions.c:333
BOOLEAN VmxAllocateHostTss(_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
Allocate a buffer for host TSS.
Definition VmxRegions.c:368
VOID DpcRoutineInitializeGuest(KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
The broadcast function which initialize the guest.
Definition DpcRoutines.c:1509
UINT64 * g_MsrBitmapInvalidMsrs
Bitmap of MSRs that cause GP.
Definition GlobalVariables.h:100

◆ VmxIsTopLevelHypervisorHyperV()

BOOLEAN VmxIsTopLevelHypervisorHyperV ( )

checks if the current top level hypervisor is Hyper-V

Returns
BOOLEAN TRUE indicates that the current top level hypervisor is Hyper-V, FALSE otherwise.
1786{
1787 INT32 ProcessorFeatures[4] = {0};
1789
1790 if (!((ULONG)(ProcessorFeatures[2]) & HYPERV_HYPERVISOR_PRESENT_BIT))
1791 {
1792 return FALSE;
1793 }
1794
1795 INT32 HypervisorVendor[4] = {0};
1797
1798 return (ULONG)(HypervisorVendor[1]) == HYPERV_CPUID_VENDOR_MICROSOFT_EBX &&
1799 (ULONG)(HypervisorVendor[2]) == HYPERV_CPUID_VENDOR_MICROSOFT_ECX &&
1800 (ULONG)(HypervisorVendor[3]) == HYPERV_CPUID_VENDOR_MICROSOFT_EDX;
1801}
VOID CpuCpuIdEx(INT32 *CpuInfo, INT32 FunctionId, INT32 SubFunctionId)
Execute CPUID with sub-leaf.
Definition PlatformIntrinsics.c:274
#define HYPERV_CPUID_VENDOR_MICROSOFT_ECX
Definition Vmx.h:211
#define HYPERV_CPUID_VENDOR_MICROSOFT_EBX
Hyper-V CPUID leaves.
Definition Vmx.h:210
#define HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS
CPUID RCX(s) - Based on Hyper-V.
Definition Vmx.h:34
#define HYPERV_HYPERVISOR_PRESENT_BIT
Definition Vmx.h:40
#define HYPERV_CPUID_VENDOR_MICROSOFT_EDX
Definition Vmx.h:212
#define CPUID_PROCESSOR_AND_PROCESSOR_FEATURE_IDENTIFIERS
CPUID Features.
Definition Constants.h:701

◆ VmxLoadVmcs()

_Use_decl_annotations_ BOOLEAN VmxLoadVmcs ( VIRTUAL_MACHINE_STATE * VCpu)

Implementation of VMPTRLD instruction.

Parameters
VCpu
Returns
BOOLEAN If vmptrld was unsuccessful then it returns false otherwise it returns false
662{
663 int VmptrldStatus;
664
665 VmptrldStatus = VmxVmptrld(&VCpu->VmcsRegionPhysicalAddress);
666
667 if (VmptrldStatus)
668 {
669 LogDebugInfo("VMCS failed to load, status : 0x%x", VmptrldStatus);
670 return FALSE;
671 }
672 return TRUE;
673}
UCHAR VmxVmptrld(UINT64 *VmcsPhysicalAddress)
VMX VMPTRLD instruction.
Definition PlatformIntrinsicsVmx.c:409

◆ VmxPerformTermination()

VOID VmxPerformTermination ( )

Terminate Vmx on all logical cores.

Returns
VOID
1105{
1106 ULONG ProcessorsCount;
1107
1108 LogDebugInfo("Terminating VMX...\n");
1109
1110 //
1111 // Get number of processors
1112 //
1113 ProcessorsCount = KeQueryActiveProcessorCount(0);
1114
1115 //
1116 // ******* Terminating Vmx *******
1117 //
1118
1119 //
1120 // Unhide (disable and de-allocate) transparent-mode
1121 //
1123 {
1125 }
1126
1127 //
1128 // Remove All the hooks if any
1129 //
1131
1132 //
1133 // Restore the state of execution trap hooks
1134 //
1136
1137 //
1138 // Broadcast to terminate Vmx
1139 //
1140 KeGenericCallDpc(DpcRoutineTerminateGuest, 0x0);
1141
1142 //
1143 // ****** De-allocatee global variables ******
1144 //
1145
1146 //
1147 // Free the buffer related to MSRs that cause #GP
1148 //
1151
1152 //
1153 // Free Identity Page Table
1154 //
1155 for (SIZE_T i = 0; i < ProcessorsCount; i++)
1156 {
1157 if (g_GuestState[i].EptPageTable != NULL)
1158 {
1159 MmFreeContiguousMemory(g_GuestState[i].EptPageTable);
1160 }
1161
1162 g_GuestState[i].EptPageTable = NULL;
1163 }
1164
1165 //
1166 // Free EptState
1167 //
1169 g_EptState = NULL;
1170
1171 //
1172 // Uninitialize memory mapper
1173 //
1175
1176 //
1177 // Free g_GuestState
1178 //
1180
1181 LogDebugInfo("VMX operation turned off successfully");
1182}
VOID EptHookUnHookAll()
Remove all hooks from the hooked pages list and invalidate TLB @detailsShould be called from Vmx Non-...
Definition EptHook.c:2451
VOID ExecTrapUninitialize()
Uinitialize the needed structure for the reversing machine.
Definition ExecTrap.c:432
VOID GlobalGuestStateFreeMemory(VOID)
Free guest state memory.
Definition GlobalVariableManagement.c:52
VOID MemoryMapperUninitialize()
uninitialize the Memory Mapper
Definition MemoryMapper.c:716
PVOID PlatformMemFreePool(PVOID BufferAddress)
Frees a memory pool.
Definition PlatformMem.c:269
IMPORT_EXPORT_VMM BOOLEAN TransparentUnhideDebuggerWrapper(DEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE *TransparentModeRequest)
Deactivate transparent-mode.
Definition HyperEvade.c:125
VOID DpcRoutineTerminateGuest(KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
The broadcast function which terminate the guest.
Definition DpcRoutines.c:1535
EPT_STATE * g_EptState
Save the state and variables related to EPT.
Definition GlobalVariables.h:50
BOOLEAN g_CheckForFootprints
Shows whether the footprints (anti-debugging and anti-hypervisor) should be checked or not.
Definition GlobalVariables.h:131
NULL()
Definition test-case-generator.py:530

◆ VmxPerformVirtualizationOnAllCores()

BOOLEAN VmxPerformVirtualizationOnAllCores ( )

Initialize essential VMX Operation tasks.

Returns
BOOLEAN Returns true if vmx is successfully initialized
268{
269 PAGED_CODE();
270
271 if (!VmxCheckVmxSupport())
272 {
273 LogError("Err, VMX is not supported in this machine");
274 return FALSE;
275 }
276
277 //
278 // Check if the top level hypervisor is Hyper-V or not
279 //
281 {
282 //
283 // The top-level hypervisor is hyper-v
284 //
286
287 LogDebugInfo(" Hyper-V is detected as the top-level hypervisor");
288 }
289 else
290 {
291 LogDebugInfo(" Hyper-V is not detected as the top-level hypervisor");
292 }
293
294 //
295 // Allocate global variable to hold Ept State
296 //
298
299 if (!g_EptState)
300 {
301 LogError("Err, insufficient memory");
302 return FALSE;
303 }
304
305 //
306 // Initialize the list of hooked pages detail
307 //
308 InitializeListHead(&g_EptState->HookedPagesList);
309
310 //
311 // Check whether EPT is supported or not
312 //
313 if (!EptCheckFeatures())
314 {
315 LogError("Err, your processor doesn't support all EPT features");
316 return FALSE;
317 }
318 else
319 {
320 //
321 // Our processor supports EPT, now let's build MTRR
322 //
323 LogDebugInfo("Your processor supports all EPT features");
324
325 //
326 // Build MTRR Map
327 //
328 if (!EptBuildMtrrMap())
329 {
330 LogError("Err, could not build MTRR memory map");
331 return FALSE;
332 }
333
334 LogDebugInfo("MTRR memory map built successfully");
335 }
336
338 {
339 //
340 // There were some errors in EptLogicalProcessorInitialize
341 //
342 return FALSE;
343 }
344
345 //
346 // Broadcast to run vmx-specific task to virtualize cores
347 //
349
350 //
351 // Everything is ok, let's return true
352 //
353 return TRUE;
354}
BOOLEAN EptLogicalProcessorInitialize(VOID)
Initialize EPT for an individual logical processor.
Definition Ept.c:865
BOOLEAN EptBuildMtrrMap(VOID)
Build MTRR Map of current physical addresses.
Definition Ept.c:167
BOOLEAN EptCheckFeatures(VOID)
Check whether EPT features are present or not.
Definition Ept.c:22
struct _EPT_STATE EPT_STATE
Main structure for saving the state of EPT among the project.
PVOID PlatformMemAllocateZeroedNonPagedPool(SIZE_T NumberOfBytes)
Allocates zeroed non-paged pool memory.
Definition PlatformMem.c:248
BOOLEAN VmxIsTopLevelHypervisorHyperV()
checks if the current top level hypervisor is Hyper-V
Definition Vmx.c:1785
BOOLEAN VmxCheckVmxSupport()
Check whether VMX Feature is supported or not.
Definition Vmx.c:20
VOID BroadcastVmxVirtualizationAllCores()
routines to broadcast virtualization and vmx initialization on all cores
Definition Broadcast.c:21
BOOLEAN g_IsTopLevelHypervisorHyperV
Whether the top level hypervisor is Hyper-V or not.
Definition GlobalVariables.h:220

◆ VmxPerformVirtualizationOnSpecificCore()

BOOLEAN VmxPerformVirtualizationOnSpecificCore ( )

Allocates Vmx regions for all logical cores (Vmxon region and Vmcs region).

Returns
BOOLEAN
363{
364 ULONG CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
365 VIRTUAL_MACHINE_STATE * VCpu = &g_GuestState[CurrentCore];
366
367 LogDebugInfo("Allocating vmx regions for logical core %d", CurrentCore);
368
369 //
370 // Enabling VMX Operation
371 //
373
374 //
375 // Fix Cr4 and Cr0 bits during VMX operation
376 //
378
379 LogDebugInfo("VMX-Operation enabled successfully");
380
381 if (!VmxAllocateVmxonRegion(VCpu))
382 {
383 LogError("Err, allocating memory for vmxon region was not successful");
384 return FALSE;
385 }
386 if (!VmxAllocateVmcsRegion(VCpu))
387 {
388 LogError("Err, allocating memory for vmcs region was not successful");
389 return FALSE;
390 }
391
392 return TRUE;
393}
VOID AsmEnableVmxOperation()
Enable VMX Operation.
VOID VmxFixCr4AndCr0Bits()
Fix values for cr0 and cr4 bits.
Definition Vmx.c:403
_Use_decl_annotations_ BOOLEAN VmxAllocateVmxonRegion(VIRTUAL_MACHINE_STATE *VCpu)
Allocates Vmxon region and set the Revision ID based on IA32_VMX_BASIC_MSR.
Definition VmxRegions.c:23
_Use_decl_annotations_ BOOLEAN VmxAllocateVmcsRegion(VIRTUAL_MACHINE_STATE *VCpu)
Allocate Vmcs region and set the Revision ID based on IA32_VMX_BASIC_MSR.
Definition VmxRegions.c:104

◆ VmxPerformVmptrst()

VOID VmxPerformVmptrst ( )

Implementation of VMPTRST instruction.

Returns
VOID
611{
612 PHYSICAL_ADDRESS VmcsPhysicalAddr;
613 VmcsPhysicalAddr.QuadPart = 0;
614 VmxVmptrst((UINT64 *)&VmcsPhysicalAddr);
615
616 LogDebugInfo("VMPTRST result : %llx", VmcsPhysicalAddr);
617}
VOID VmxVmptrst(UINT64 *VmcsPhysicalAddress)
VMX VMPTRST instruction.
Definition PlatformIntrinsicsVmx.c:339

◆ VmxPerformVmresume()

VOID VmxPerformVmresume ( )

Resume VM using the VMRESUME instruction.

Returns
VOID
907{
908 UINT32 ErrorCode = 0;
909
910 VmxVmresume();
911
912 //
913 // if VMRESUME succeed will never be here !
914 //
915
916 VmxVmread32P(VMCS_VM_INSTRUCTION_ERROR, &ErrorCode);
917
918 VmxVmxoff();
919
920 //
921 // It's such a bad error because we don't where to go !
922 // prefer to break
923 //
924
925 LogError("Err, in executing VMRESUME, status : 0x%llx, last VM-exit reason: 0x%x",
926 ErrorCode,
927 g_GuestState[KeGetCurrentProcessorNumberEx(NULL)].ExitReason);
928}
UCHAR VmxVmread32P(size_t Field, UINT32 *FieldValue)
VMX VMREAD instruction (32-bit, pointer variant).
Definition PlatformIntrinsicsVmx.c:227
VOID VmxVmresume(VOID)
VMX VMRESUME instruction.
Definition PlatformIntrinsicsVmx.c:356

◆ VmxPerformVmxoff()

VOID VmxPerformVmxoff ( VIRTUAL_MACHINE_STATE * VCpu)

Prepare and execute Vmxoff instruction.

Parameters
VCpuThe virtual processor's state
Returns
VOID
992{
993 UINT64 GuestRSP = 0; // Save a pointer to guest rsp for times that we want to return to previous guest stateS
994 UINT64 GuestRIP = 0; // Save a pointer to guest rip for times that we want to return to previous guest state
995 UINT64 GuestCr3 = 0;
996 UINT64 ExitInstructionLength = 0;
997
998 //
999 // According to SimpleVisor :
1000 // Our callback routine may have interrupted an arbitrary user process,
1001 // and therefore not a thread running with a system-wide page directory.
1002 // Therefore if we return back to the original caller after turning off
1003 // VMX, it will keep our current "host" CR3 value which we set on entry
1004 // to the PML4 of the SYSTEM process. We want to return back with the
1005 // correct value of the "guest" CR3, so that the currently executing
1006 // process continues to run with its expected address space mappings.
1007 //
1008
1009 VmxVmread64P(VMCS_GUEST_CR3, &GuestCr3);
1010 CpuWriteCr3(GuestCr3);
1011
1012 //
1013 // Read guest rsp and rip
1014 //
1015 VmxVmread64P(VMCS_GUEST_RIP, &GuestRIP);
1016 VmxVmread64P(VMCS_GUEST_RSP, &GuestRSP);
1017
1018 //
1019 // Read instruction length
1020 //
1021 VmxVmread64P(VMCS_VMEXIT_INSTRUCTION_LENGTH, &ExitInstructionLength);
1022 GuestRIP += ExitInstructionLength;
1023
1024 //
1025 // Set the previous register states
1026 //
1027 VCpu->VmxoffState.GuestRip = GuestRIP;
1028 VCpu->VmxoffState.GuestRsp = GuestRSP;
1029
1030 //
1031 // Notify the Vmexit handler that VMX already turned off
1032 //
1034
1035 //
1036 // Restore the previous FS, GS , GDTR and IDTR register as patchguard might find the modified
1037 //
1039
1040 //
1041 // Restore XMM registers
1042 // We restore XMM registers here because we are going to execute vmxoff instruction
1043 // which enables interrupts and we don't want to lose the XMM registers
1044 // since immediately after vmxoff, an interrupt might occur and context switch
1045 // might change the XMM registers
1046 //
1047 AsmVmxoffRestoreXmmRegs((UINT64)VCpu->XmmRegs);
1048
1049 //
1050 // Before using vmxoff, you first need to use vmclear on any VMCSes that you want to be able to use again.
1051 // See sections 24.1 and 24.11 of the SDM.
1052 //
1053 VmxClearVmcsState(VCpu);
1054
1055 //
1056 // Execute Vmxoff
1057 //
1058 VmxVmxoff();
1059
1060 //
1061 // *** Note: After executing VMXOFF, XMM registers should not be used anymore
1062 // Since we already restored them ***
1063 //
1064
1065 //
1066 // Indicate the current core is not currently virtualized
1067 //
1068 VCpu->HasLaunched = FALSE;
1069
1070 //
1071 // Now that VMX is OFF, we have to unset vmx-enable bit on cr4
1072 //
1074}
VOID HvRestoreRegisters()
Reset GDTR/IDTR and other old when you do vmxoff as the patchguard will detect them left modified.
Definition Hv.c:491
VOID AsmVmxoffRestoreXmmRegs(UINT64 XmmRegs)
Restore XMM registers.
_Use_decl_annotations_ BOOLEAN VmxClearVmcsState(VIRTUAL_MACHINE_STATE *VCpu)
Clearing Vmcs status using vmclear instruction.
Definition Vmx.c:628
#define REG_CR4_VMXE
Definition Constants.h:649
GUEST_XMM_REGS * XmmRegs
Definition State.h:327
VMX_VMXOFF_STATE VmxoffState
Definition State.h:350
UINT64 GuestRip
Definition State.h:169
UINT64 GuestRsp
Definition State.h:170
BOOLEAN IsVmxoffExecuted
Definition State.h:168

◆ VmxReturnInstructionPointerForVmxoff()

UINT64 VmxReturnInstructionPointerForVmxoff ( )

Get the RIP of guest (VMCS_GUEST_RIP) in the case of return from VMXOFF.

Returns
UINT64 Returns the instruction pointer, to change in the case of Vmxoff
1094{
1095 return g_GuestState[KeGetCurrentProcessorNumberEx(NULL)].VmxoffState.GuestRip;
1096}

◆ VmxReturnStackPointerForVmxoff()

UINT64 VmxReturnStackPointerForVmxoff ( )

Get the RIP of guest (VMCS_GUEST_RIP) in the case of return from VMXOFF.

Returns
UINT64 Returns the stack pointer, to change in the case of Vmxoff
1083{
1084 return g_GuestState[KeGetCurrentProcessorNumberEx(NULL)].VmxoffState.GuestRsp;
1085}

◆ VmxSetupVmcs()

_Use_decl_annotations_ BOOLEAN VmxSetupVmcs ( VIRTUAL_MACHINE_STATE * VCpu,
PVOID GuestStack )

Create and Configure a Vmcs Layout.

Parameters
VCpu
GuestStack
Returns
BOOLEAN
685{
686 UINT32 CpuBasedVmExecControls;
687 UINT32 SecondaryProcBasedVmExecControls;
688 PVOID HostRsp;
689 UINT64 GdtBase = 0;
690 IA32_VMX_BASIC_REGISTER VmxBasicMsr = {0};
692
693 //
694 // Reading IA32_VMX_BASIC_MSR
695 //
696 VmxBasicMsr.AsUInt = CpuReadMsr(IA32_VMX_BASIC);
697
698 VmxVmwrite64(VMCS_HOST_ES_SELECTOR, AsmGetEs() & 0xF8);
699 VmxVmwrite64(VMCS_HOST_CS_SELECTOR, AsmGetCs() & 0xF8);
700 VmxVmwrite64(VMCS_HOST_SS_SELECTOR, AsmGetSs() & 0xF8);
701 VmxVmwrite64(VMCS_HOST_DS_SELECTOR, AsmGetDs() & 0xF8);
702 VmxVmwrite64(VMCS_HOST_FS_SELECTOR, AsmGetFs() & 0xF8);
703 VmxVmwrite64(VMCS_HOST_GS_SELECTOR, AsmGetGs() & 0xF8);
704 VmxVmwrite64(VMCS_HOST_TR_SELECTOR, AsmGetTr() & 0xF8);
705
706 //
707 // Setting the link pointer to the required value for 4KB VMCS
708 //
709 VmxVmwrite64(VMCS_GUEST_VMCS_LINK_POINTER, ~0ULL);
710
711 VmxVmwrite64(VMCS_GUEST_DEBUGCTL, CpuReadMsr(IA32_DEBUGCTL) & 0xFFFFFFFF);
712 VmxVmwrite64(VMCS_GUEST_DEBUGCTL_HIGH, CpuReadMsr(IA32_DEBUGCTL) >> 32);
713
714 //
715 // ******* Time-stamp counter offset *******
716 //
717 VmxVmwrite64(VMCS_CTRL_TSC_OFFSET, 0);
718
719 VmxVmwrite64(VMCS_CTRL_PAGEFAULT_ERROR_CODE_MASK, 0);
720 VmxVmwrite64(VMCS_CTRL_PAGEFAULT_ERROR_CODE_MATCH, 0);
721
722 VmxVmwrite64(VMCS_CTRL_VMEXIT_MSR_STORE_COUNT, 0);
723 VmxVmwrite64(VMCS_CTRL_VMEXIT_MSR_LOAD_COUNT, 0);
724
725 VmxVmwrite64(VMCS_CTRL_VMENTRY_MSR_LOAD_COUNT, 0);
726 VmxVmwrite64(VMCS_CTRL_VMENTRY_INTERRUPTION_INFORMATION_FIELD, 0);
727
728 GdtBase = AsmGetGdtBase();
729
738
739 VmxVmwrite64(VMCS_GUEST_FS_BASE, CpuReadMsr(IA32_FS_BASE));
740 VmxVmwrite64(VMCS_GUEST_GS_BASE, CpuReadMsr(IA32_GS_BASE));
741
742 CpuBasedVmExecControls = HvAdjustControls(
743 IA32_VMX_PROCBASED_CTLS_USE_IO_BITMAPS_FLAG |
744 IA32_VMX_PROCBASED_CTLS_USE_MSR_BITMAPS_FLAG |
745 IA32_VMX_PROCBASED_CTLS_ACTIVATE_SECONDARY_CONTROLS_FLAG,
746 VmxBasicMsr.VmxControls ? IA32_VMX_TRUE_PROCBASED_CTLS : IA32_VMX_PROCBASED_CTLS);
747
748 VmxVmwrite64(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, CpuBasedVmExecControls);
749
750 LogDebugInfo("CPU Based VM Exec Controls (Based on %s) : 0x%x",
751 VmxBasicMsr.VmxControls ? "IA32_VMX_TRUE_PROCBASED_CTLS" : "IA32_VMX_PROCBASED_CTLS",
752 CpuBasedVmExecControls);
753 UINT32 SecondaryProcBasedVmExecControlsFlags = IA32_VMX_PROCBASED_CTLS2_ENABLE_RDTSCP_FLAG |
754 IA32_VMX_PROCBASED_CTLS2_ENABLE_EPT_FLAG |
755 IA32_VMX_PROCBASED_CTLS2_ENABLE_INVPCID_FLAG |
756 IA32_VMX_PROCBASED_CTLS2_ENABLE_XSAVES_FLAG |
757 IA32_VMX_PROCBASED_CTLS2_ENABLE_USER_WAIT_PAUSE_FLAG;
758
760 {
761 SecondaryProcBasedVmExecControlsFlags |= IA32_VMX_PROCBASED_CTLS2_ENABLE_VPID_FLAG;
762 }
763 SecondaryProcBasedVmExecControls = HvAdjustControls(SecondaryProcBasedVmExecControlsFlags, IA32_VMX_PROCBASED_CTLS2);
764
765 VmxVmwrite64(VMCS_CTRL_SECONDARY_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, SecondaryProcBasedVmExecControls);
766
767 LogDebugInfo("Secondary Proc Based VM Exec Controls (IA32_VMX_PROCBASED_CTLS2) : 0x%x", SecondaryProcBasedVmExecControls);
768
769 VmxVmwrite64(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS,
771 0,
772 VmxBasicMsr.VmxControls ? IA32_VMX_TRUE_PINBASED_CTLS : IA32_VMX_PINBASED_CTLS));
773
774 VmxVmwrite64(VMCS_CTRL_PRIMARY_VMEXIT_CONTROLS,
776 IA32_VMX_EXIT_CTLS_HOST_ADDRESS_SPACE_SIZE_FLAG |
777 IA32_VMX_EXIT_CTLS_LOAD_IA32_CET_STATE_FLAG,
778 VmxBasicMsr.VmxControls ? IA32_VMX_TRUE_EXIT_CTLS : IA32_VMX_EXIT_CTLS));
779
780 VmxVmwrite64(VMCS_CTRL_VMENTRY_CONTROLS,
782 IA32_VMX_ENTRY_CTLS_IA32E_MODE_GUEST_FLAG |
783 IA32_VMX_ENTRY_CTLS_LOAD_CET_STATE_FLAG,
784 VmxBasicMsr.VmxControls ? IA32_VMX_TRUE_ENTRY_CTLS : IA32_VMX_ENTRY_CTLS));
785
786 VmxVmwrite64(VMCS_CTRL_CR0_GUEST_HOST_MASK, 0);
787 VmxVmwrite64(VMCS_CTRL_CR4_GUEST_HOST_MASK, 0);
788
789 VmxVmwrite64(VMCS_CTRL_CR0_READ_SHADOW, 0);
790 VmxVmwrite64(VMCS_CTRL_CR4_READ_SHADOW, 0);
791
792 VmxVmwrite64(VMCS_GUEST_CR0, CpuReadCr0());
793 VmxVmwrite64(VMCS_GUEST_CR3, CpuReadCr3());
794 VmxVmwrite64(VMCS_GUEST_CR4, CpuReadCr4());
795
796 VmxVmwrite64(VMCS_GUEST_DR7, 0x400);
797
798 VmxVmwrite64(VMCS_HOST_CR0, CpuReadCr0());
799 VmxVmwrite64(VMCS_HOST_CR4, CpuReadCr4());
800
801 //
802 // Because we may be executing in an arbitrary user-mode, process as part
803 // of the DPC interrupt we execute in We have to save Cr3, for VMCS_HOST_CR3
804 //
805
807
808 VmxVmwrite64(VMCS_GUEST_GDTR_BASE, AsmGetGdtBase());
809 VmxVmwrite64(VMCS_GUEST_IDTR_BASE, AsmGetIdtBase());
810
811 VmxVmwrite64(VMCS_GUEST_GDTR_LIMIT, AsmGetGdtLimit());
812 VmxVmwrite64(VMCS_GUEST_IDTR_LIMIT, AsmGetIdtLimit());
813
814 VmxVmwrite64(VMCS_GUEST_RFLAGS, AsmGetRflags());
815
816 VmxVmwrite64(VMCS_GUEST_SYSENTER_CS, CpuReadMsr(IA32_SYSENTER_CS));
817 VmxVmwrite64(VMCS_GUEST_SYSENTER_EIP, CpuReadMsr(IA32_SYSENTER_EIP));
818 VmxVmwrite64(VMCS_GUEST_SYSENTER_ESP, CpuReadMsr(IA32_SYSENTER_ESP));
819
820#if USE_DEFAULT_OS_GDT_AS_HOST_GDT == FALSE
821
823
824 VmxVmwrite64(VMCS_HOST_TR_BASE, SegmentSelector.Base);
825 VmxVmwrite64(VMCS_HOST_GDTR_BASE, VCpu->HostGdt);
826
827#else
828
830
831 VmxVmwrite64(VMCS_HOST_TR_BASE, SegmentSelector.Base);
832 VmxVmwrite64(VMCS_HOST_GDTR_BASE, AsmGetGdtBase());
833
834#endif // USE_DEFAULT_OS_GDT_AS_HOST_GDT == FALSE
835
836 VmxVmwrite64(VMCS_HOST_FS_BASE, CpuReadMsr(IA32_FS_BASE));
837 VmxVmwrite64(VMCS_HOST_GS_BASE, CpuReadMsr(IA32_GS_BASE));
838
839#if USE_DEFAULT_OS_IDT_AS_HOST_IDT == FALSE
840
841 VmxVmwrite64(VMCS_HOST_IDTR_BASE, VCpu->HostIdt);
842
843#else
844
845 VmxVmwrite64(VMCS_HOST_IDTR_BASE, AsmGetIdtBase());
846
847#endif // USE_DEFAULT_OS_IDT_AS_HOST_IDT == FALSE
848
849 VmxVmwrite64(VMCS_HOST_SYSENTER_CS, CpuReadMsr(IA32_SYSENTER_CS));
850 VmxVmwrite64(VMCS_HOST_SYSENTER_EIP, CpuReadMsr(IA32_SYSENTER_EIP));
851 VmxVmwrite64(VMCS_HOST_SYSENTER_ESP, CpuReadMsr(IA32_SYSENTER_ESP));
852
853 //
854 // Set MSR Bitmaps
855 //
856 VmxVmwrite64(VMCS_CTRL_MSR_BITMAP_ADDRESS, VCpu->MsrBitmapPhysicalAddress);
857
858 //
859 // Set I/O Bitmaps
860 //
861 VmxVmwrite64(VMCS_CTRL_IO_BITMAP_A_ADDRESS, VCpu->IoBitmapPhysicalAddressA);
862 VmxVmwrite64(VMCS_CTRL_IO_BITMAP_B_ADDRESS, VCpu->IoBitmapPhysicalAddressB);
863
864 //
865 // Set up EPT
866 //
867 VmxVmwrite64(VMCS_CTRL_EPT_POINTER, VCpu->EptPointer.AsUInt);
868
869 //
870 // Set up VPID
871
872 //
873 // For all processors, we will use a VPID = 1. This allows the processor to separate caching
874 // of EPT structures away from the regular OS page translation tables in the TLB.
875 //
877
878 //
879 // setup guest rsp
880 //
881 VmxVmwrite64(VMCS_GUEST_RSP, (UINT64)GuestStack);
882
883 //
884 // setup guest rip
885 //
886 VmxVmwrite64(VMCS_GUEST_RIP, (UINT64)AsmVmxRestoreState);
887
888 //
889 // Stack should be aligned to 16 because we wanna save XMM and FPU registers and those instructions
890 // needs alignment to 16
891 //
892 HostRsp = (PVOID)((UINT64)VCpu->VmmStack + VMM_STACK_SIZE - 1);
893 HostRsp = ((PVOID)((ULONG_PTR)(HostRsp) & ~(16 - 1)));
894 VmxVmwrite64(VMCS_HOST_RSP, (UINT64)HostRsp);
895 VmxVmwrite64(VMCS_HOST_RIP, (UINT64)AsmVmexitHandler);
896
897 return TRUE;
898}
UINT32 HvAdjustControls(UINT32 Ctl, UINT32 Msr)
Adjust controls for VMCS based on processor capability.
Definition Hv.c:23
VOID HvFillGuestSelectorData(PVOID GdtBase, UINT32 SegmentRegister, UINT16 Selector)
Fill the guest's selector data.
Definition Hv.c:272
UINT16 AsmGetSs()
Get SS Register.
UINT16 AsmGetFs()
Get FS Register.
UINT64 AsmGetIdtBase()
Get IDT base.
VOID AsmVmexitHandler()
Vm-exit handler.
UINT16 AsmGetCs()
Get CS Register.
UINT16 AsmGetGdtLimit()
Get GDT Limit.
VOID AsmVmxRestoreState()
Restore state on vmx.
UINT16 AsmGetEs()
Get ES Register.
UINT64 AsmGetGdtBase()
get GDT base
UINT16 AsmGetDs()
Get DS Register.
UINT16 AsmGetGs()
Get GS Register.
UINT16 AsmGetRflags()
Get R/EFLAGS.
UINT16 AsmGetTr()
Get TR Register.
UINT16 AsmGetLdtr()
Get LDTR Register.
UINT16 AsmGetIdtLimit()
Get IDT limit.
UINT64 LayoutGetSystemDirectoryTableBase()
Find cr3 of system process.
Definition Layout.c:90
UCHAR VmxVmwrite64(size_t Field, UINT64 FieldValue)
VMX VMWRITE instruction (64-bit).
Definition PlatformIntrinsicsVmx.c:273
_Use_decl_annotations_ BOOLEAN SegmentGetDescriptor(PUCHAR GdtBase, UINT16 Selector, PVMX_SEGMENT_SELECTOR SegmentSelector)
Get Segment Descriptor.
Definition Segmentation.c:24
_In_ UINT16 _Out_ PVMX_SEGMENT_SELECTOR SegmentSelector
Definition Segmentation.h:51
#define VIRTUAL_PROCESSOR_ID
Definition Vmx.h:222
#define VMM_STACK_SIZE
Stack Size.
Definition Vmx.h:65
#define VMCS_GUEST_DEBUGCTL_HIGH
Definition Vmx.h:221
#define VPID_TAG
VPID Tag.
Definition Vpid.h:30
void * PVOID
Definition BasicTypes.h:56
@ TR
Definition Constants.h:601
@ LDTR
Definition Constants.h:600
@ FS
Definition Constants.h:598
@ ES
Definition Constants.h:594
@ CS
Definition Constants.h:595
@ GS
Definition Constants.h:599
@ DS
Definition Constants.h:597
@ SS
Definition Constants.h:596
struct _VMX_SEGMENT_SELECTOR VMX_SEGMENT_SELECTOR
Segment selector.
BOOLEAN g_IsVpidSupported
Whether VPID is supported or not.
Definition GlobalVariables.h:215
UINT64 MsrBitmapPhysicalAddress
Definition State.h:338
UINT64 HostGdt
Definition State.h:356
EPT_POINTER EptPointer
Definition State.h:363
UINT64 IoBitmapPhysicalAddressA
Definition State.h:340
UINT64 VmmStack
Definition State.h:336
UINT64 HostIdt
Definition State.h:355
UINT64 IoBitmapPhysicalAddressB
Definition State.h:342

◆ VmxTerminate()

BOOLEAN VmxTerminate ( )

Broadcast to terminate VMX on all logical cores.

Returns
BOOLEAN Returns true if vmxoff successfully executed in vmcall or otherwise returns false
562{
563 NTSTATUS Status = STATUS_SUCCESS;
564 ULONG CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
565 VIRTUAL_MACHINE_STATE * VCpu = &g_GuestState[CurrentCore];
566
567 //
568 // Execute Vmcall to to turn off vmx from Vmx root mode
569 //
571
572 if (Status == STATUS_SUCCESS)
573 {
574 LogDebugInfo("VMX terminated on logical core %d\n", CurrentCore);
575
576 //
577 // Free the destination memory
578 //
579 MmFreeContiguousMemory((PVOID)VCpu->VmxonRegionVirtualAddress);
580 MmFreeContiguousMemory((PVOID)VCpu->VmcsRegionVirtualAddress);
585#if USE_DEFAULT_OS_IDT_AS_HOST_IDT == FALSE
587#endif // USE_DEFAULT_OS_IDT_AS_HOST_IDT == FALSE
588
589#if USE_DEFAULT_OS_GDT_AS_HOST_GDT == FALSE
592#endif // USE_DEFAULT_OS_GDT_AS_HOST_GDT == FALSE
593
594#if USE_INTERRUPT_STACK_TABLE == TRUE
596#endif // USE_INTERRUPT_STACK_TABLE == FALSE
597
598 return TRUE;
599 }
600
601 return FALSE;
602}
#define VMCALL_VMXOFF
VMCALL to Call VMXOFF to turn off the hypervisor.
Definition Vmcall.h:28
#define NULL64_ZERO
Definition BasicTypes.h:111
UINT64 VmxonRegionVirtualAddress
Definition State.h:333
UINT64 HostInterruptStack
Definition State.h:358
UINT64 IoBitmapVirtualAddressB
Definition State.h:341
UINT64 MsrBitmapVirtualAddress
Definition State.h:337
UINT64 HostTss
Definition State.h:357
UINT64 IoBitmapVirtualAddressA
Definition State.h:339
UINT64 VmcsRegionVirtualAddress
Definition State.h:335

◆ VmxVirtualizeCurrentSystem()

BOOLEAN VmxVirtualizeCurrentSystem ( PVOID GuestStack)

Initialize VMX Operation.

Parameters
GuestStackGuest stack for the this core (VMCS_GUEST_RSP)
Returns
BOOLEAN This function won't return true as when Vmlaunch is executed the rest of the function never executes but returning FALSE is an indication of error
468{
469 UINT64 ErrorCode = 0;
470 ULONG CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
471 VIRTUAL_MACHINE_STATE * VCpu = &g_GuestState[CurrentCore];
472
473 LogDebugInfo("Virtualizing current system (logical core : 0x%x)", CurrentCore);
474
475#if USE_DEFAULT_OS_IDT_AS_HOST_IDT == FALSE
476
477 //
478 // Prepare Host IDT
479 //
481#endif // USE_DEFAULT_OS_IDT_AS_HOST_IDT == FALSE
482
483#if USE_DEFAULT_OS_GDT_AS_HOST_GDT == FALSE
484
485 //
486 // Prepare Host GDT and TSS
487 //
488 SegmentPrepareHostGdt((SEGMENT_DESCRIPTOR_32 *)AsmGetGdtBase(),
490 AsmGetTr(),
491 VCpu->HostInterruptStack,
492 (SEGMENT_DESCRIPTOR_32 *)VCpu->HostGdt,
493 (TASK_STATE_SEGMENT_64 *)VCpu->HostTss);
494
495#endif // USE_DEFAULT_OS_GDT_AS_HOST_GDT == FALSE
496
497 //
498 // Clear the VMCS State
499 //
500 if (!VmxClearVmcsState(VCpu))
501 {
502 LogError("Err, failed to clear vmcs");
503 return FALSE;
504 }
505
506 //
507 // Load VMCS (Set the Current VMCS)
508 //
509 if (!VmxLoadVmcs(VCpu))
510 {
511 LogError("Err, failed to load vmcs");
512 return FALSE;
513 }
514
515 LogDebugInfo("Setting up VMCS for current logical core");
516
517 VmxSetupVmcs(VCpu, GuestStack);
518
519 LogDebugInfo("Executing VMLAUNCH on logical core %d", CurrentCore);
520
521 //
522 // Setting the state to indicate current core is currently virtualized
523 //
524
525 VCpu->HasLaunched = TRUE;
526
527 VmxVmlaunch();
528
529 //
530 // ******** if Vmlaunch succeed will never be here ! ********
531 //
532
533 //
534 // If failed, then indicate that current core is not currently virtualized
535 //
536 VCpu->HasLaunched = FALSE;
537
538 //
539 // Read error code firstly
540 //
541 VmxVmread64P(VMCS_VM_INSTRUCTION_ERROR, &ErrorCode);
542
543 LogError("Err, unable to execute VMLAUNCH, status : 0x%llx", ErrorCode);
544
545 //
546 // Then Execute Vmxoff
547 //
548 VmxVmxoff();
549 LogError("Err, VMXOFF Executed Successfully but it was because of an error");
550
551 return FALSE;
552}
VOID IdtEmulationPrepareHostIdt(_Inout_ VIRTUAL_MACHINE_STATE *VCpu)
Prepare Host IDT.
Definition IdtEmulation.c:117
VOID VmxVmlaunch(VOID)
VMX VMLAUNCH instruction.
Definition PlatformIntrinsicsVmx.c:390
VOID SegmentPrepareHostGdt(SEGMENT_DESCRIPTOR_32 *OsGdtBase, UINT16 OsGdtLimit, UINT16 TrSelector, UINT64 HostStack, SEGMENT_DESCRIPTOR_32 *AllocatedHostGdt, TASK_STATE_SEGMENT_64 *AllocatedHostTss)
Initialize the host GDT.
Definition Segmentation.c:95
_Use_decl_annotations_ BOOLEAN VmxLoadVmcs(VIRTUAL_MACHINE_STATE *VCpu)
Implementation of VMPTRLD instruction.
Definition Vmx.c:661
_Use_decl_annotations_ BOOLEAN VmxSetupVmcs(VIRTUAL_MACHINE_STATE *VCpu, PVOID GuestStack)
Create and Configure a Vmcs Layout.
Definition Vmx.c:684

◆ VmxVmfunc()

UINT64 VmxVmfunc ( UINT32 EptpIndex,
UINT32 Function )

VMFUNC instruction.

Should be executed in VMX NON-root

Parameters
EptpIndex
Function
Returns
UINT64
941{
942 //
943 // *** To be executed in VMX non-root ***
944 //
945
946 //
947 // Description from : https://users.cs.utah.edu/~aburtsev/lls-sem/index.php?n=Main.VMFUNCNotes
948 //
949 // VMFUNC is a new Intel primitive that allows to change an EPT page table underneath a VT-x VM without exiting into the hypervisor
950 // Effectively, it's a page table switch in hardware and thus it allows one to build a fast context switch
951 //
952
953 //
954 // Each VT-x virtual machine is configured with a Virtual Machine Control Structure (VMCS)
955 // This is a page of memory in which the VMM writes configuration data for things like how interrupts are handled,
956 // initial control register values during guest entry, and a whole bunch of other things
957 //
958 // One of those other things is a pointer to a page of candidate EPT pointers. These are pointers to different EPT
959 // page table hierarchies, each one giving a possibly different physical -> machine mapping. The VMM sets up this page
960 // of EPT pointers and has to also turn on a couple other settings in the VMCS to fully enable EPT switching via VMFUNC
961 //
962 // In non-root operation (inside a VM) code running in any privilege level can switch EPT hierarchies through the following
963 // steps:
964 //
965 // Storing 0 in %rax (EPT switching is VMFUNC 0)
966 // Storing the index into the candidate EPT table in %rcx
967 // Invoking the VMFUNC instruction
968 // The processor will switch EPTs. Invoking VMFUNC will not cause a VM Exit
969 //
970 // All of this is detailed in the Intel SDM Volume 3, 25.5.5.3 "EPT Switching"
971 //
972 // It is worth noting that this will not change/save values in control registers (e.g. %cr3), general purpose registers,
973 // and so on. It's up to the code and VMM to set things up so it all works gracefully
974 //
975
976 //
977 // Are TLBs flushed ? No, unless VPIDs are not being used(which I, Charlie, would say is rare)
978 // See Intel SDM Volume 3, 25.5.5.3 "EPT Switching" and 28.3.3.1 "Operations that Invalidate Cached Mappings"
979 //
980
981 return AsmVmfunc(EptpIndex, Function);
982}
UINT64 AsmVmfunc(ULONG EptpIndex, ULONG Function)
VMFUNC instruction.