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

Contains the headers relating to EPT structures, MTRR and all basic Hooking structures. More...

Go to the source code of this file.

Classes

struct  _MTRR_RANGE_DESCRIPTOR
 MTRR Descriptor. More...
union  _IA32_MTRR_FIXED_RANGE_TYPE
 Fixed range MTRR. More...
struct  _EPT_STATE
 Main structure for saving the state of EPT among the project. More...
struct  _VMM_EPT_DYNAMIC_SPLIT
 Split 2MB granularity to 4 KB granularity. More...

Macros

#define PAGE_ATTRIB_READ   0x2
 Page attributes for internal use.
#define PAGE_ATTRIB_WRITE   0x4
#define PAGE_ATTRIB_EXEC   0x8
#define PAGE_ATTRIB_EXEC_HIDDEN_HOOK   0x10
#define SIZE_2_MB   ((SIZE_T)(512 * PAGE_SIZE))
 Integer 2MB.
#define SIZE_1_GB   ((SIZE_T)(512 * SIZE_2_MB))
 Integer 1GB.
#define SIZE_512_GB   ((SIZE_T)(512 * SIZE_1_GB))
 Integer 512GB.
#define ADDRMASK_EPT_PML1_OFFSET(_VAR_)
 Offset into the 1st paging structure (4096 byte).
#define ADDRMASK_EPT_PML1_INDEX(_VAR_)
 Index of the 1st paging structure (4096 byte).
#define ADDRMASK_EPT_PML2_INDEX(_VAR_)
 Index of the 2nd paging structure (2MB).
#define ADDRMASK_EPT_PML3_INDEX(_VAR_)
 Index of the 3rd paging structure (1GB).
#define ADDRMASK_EPT_PML4_INDEX(_VAR_)
 Index of the 4th paging structure (512GB).
#define MAX_VARIABLE_RANGE_MTRRS   255
 Architecturally defined number of variable range MTRRs.
#define NUM_FIXED_RANGE_MTRRS   ((1 + 2 + 8) * RTL_NUMBER_OF_FIELD(IA32_MTRR_FIXED_RANGE_TYPE, s.Types))
 Architecturally defined number of fixed range MTRRs. 1 register for 64k, 2 registers for 16k, 8 registers for 4k, and each register has 8 ranges as per "Fixed Range MTRRs" states.
#define NUM_MTRR_ENTRIES   (MAX_VARIABLE_RANGE_MTRRS + NUM_FIXED_RANGE_MTRRS)
 Total number of MTRR descriptors to store.

Typedefs

typedef struct _MTRR_RANGE_DESCRIPTOR MTRR_RANGE_DESCRIPTOR
 MTRR Descriptor.
typedef struct _MTRR_RANGE_DESCRIPTORPMTRR_RANGE_DESCRIPTOR
typedef union _IA32_MTRR_FIXED_RANGE_TYPE IA32_MTRR_FIXED_RANGE_TYPE
 Fixed range MTRR.
typedef struct _EPT_STATE EPT_STATE
 Main structure for saving the state of EPT among the project.
typedef struct _EPT_STATEPEPT_STATE
typedef struct _VMM_EPT_DYNAMIC_SPLIT VMM_EPT_DYNAMIC_SPLIT
 Split 2MB granularity to 4 KB granularity.
typedef struct _VMM_EPT_DYNAMIC_SPLITPVMM_EPT_DYNAMIC_SPLIT

Functions

BOOLEAN EptSetupPML2Entry (PVMM_EPT_PAGE_TABLE EptPageTable, PEPT_PML2_ENTRY NewEntry, SIZE_T PageFrameNumber)
 Set up PML2 Entries.
BOOLEAN EptHandlePageHookExit (_Inout_ VIRTUAL_MACHINE_STATE *VCpu, _In_ VMX_EXIT_QUALIFICATION_EPT_VIOLATION ViolationQualification, _In_ UINT64 GuestPhysicalAddr)
BOOLEAN EptCheckFeatures (VOID)
 Check for EPT Features.
BOOLEAN EptBuildMtrrMap (VOID)
 Build MTRR Map.
PVMM_EPT_PAGE_TABLE EptAllocateAndCreateIdentityPageTable (VOID)
 Allocates page maps and create identity page table.
BOOLEAN EptSplitLargePage (PVMM_EPT_PAGE_TABLE EptPageTable, BOOLEAN UsePreAllocatedBuffer, SIZE_T PhysicalAddress)
 Convert large pages to 4KB pages.
PEPT_PML2_ENTRY EptGetPml2Entry (PVMM_EPT_PAGE_TABLE EptPageTable, SIZE_T PhysicalAddress)
 Split 2MB (LargePage) into 4kb pages.
BOOLEAN EptLogicalProcessorInitialize (VOID)
 Initialize EPT Table based on Processor Index.
BOOLEAN EptHandleEptViolation (VIRTUAL_MACHINE_STATE *VCpu)
 Handle EPT Violation.
PEPT_PML1_ENTRY EptGetPml1Entry (PVMM_EPT_PAGE_TABLE EptPageTable, SIZE_T PhysicalAddress)
 Get the PML1 Entry of a special address.
PVOID EptGetPml1OrPml2Entry (PVMM_EPT_PAGE_TABLE EptPageTable, SIZE_T PhysicalAddress, BOOLEAN *IsLargePage)
 Get the PML1 entry for this physical address if the large page is available then large page of Pml2 is returned.
VOID EptHandleMisconfiguration (VOID)
 Handle Ept Misconfigurations.
VOID EptSetPML1AndInvalidateTLB (_Inout_ VIRTUAL_MACHINE_STATE *VCpu, _Out_ PEPT_PML1_ENTRY EntryAddress, _In_ EPT_PML1_ENTRY EntryValue, _In_ _Strict_type_match_ INVEPT_TYPE InvalidationType)
 This function set the specific PML1 entry in a spinlock protected area then invalidate the TLB , this function should be called from vmx root-mode.
BOOLEAN EptCheckAndHandleBreakpoint (VIRTUAL_MACHINE_STATE *VCpu)
 Check if the breakpoint vm-exit relates to EPT hook or not.

Detailed Description

Contains the headers relating to EPT structures, MTRR and all basic Hooking structures.

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

Macro Definition Documentation

◆ ADDRMASK_EPT_PML1_INDEX

#define ADDRMASK_EPT_PML1_INDEX ( _VAR_)
Value:
(((_VAR_) & 0x1FF000ULL) >> 12)

Index of the 1st paging structure (4096 byte).

◆ ADDRMASK_EPT_PML1_OFFSET

#define ADDRMASK_EPT_PML1_OFFSET ( _VAR_)
Value:
((_VAR_) & 0xFFFULL)

Offset into the 1st paging structure (4096 byte).

◆ ADDRMASK_EPT_PML2_INDEX

#define ADDRMASK_EPT_PML2_INDEX ( _VAR_)
Value:
(((_VAR_) & 0x3FE00000ULL) >> 21)

Index of the 2nd paging structure (2MB).

◆ ADDRMASK_EPT_PML3_INDEX

#define ADDRMASK_EPT_PML3_INDEX ( _VAR_)
Value:
(((_VAR_) & 0x7FC0000000ULL) >> 30)

Index of the 3rd paging structure (1GB).

◆ ADDRMASK_EPT_PML4_INDEX

#define ADDRMASK_EPT_PML4_INDEX ( _VAR_)
Value:
(((_VAR_) & 0xFF8000000000ULL) >> 39)

Index of the 4th paging structure (512GB).

◆ MAX_VARIABLE_RANGE_MTRRS

#define MAX_VARIABLE_RANGE_MTRRS   255

Architecturally defined number of variable range MTRRs.

◆ NUM_FIXED_RANGE_MTRRS

#define NUM_FIXED_RANGE_MTRRS   ((1 + 2 + 8) * RTL_NUMBER_OF_FIELD(IA32_MTRR_FIXED_RANGE_TYPE, s.Types))

Architecturally defined number of fixed range MTRRs. 1 register for 64k, 2 registers for 16k, 8 registers for 4k, and each register has 8 ranges as per "Fixed Range MTRRs" states.

◆ NUM_MTRR_ENTRIES

#define NUM_MTRR_ENTRIES   (MAX_VARIABLE_RANGE_MTRRS + NUM_FIXED_RANGE_MTRRS)

Total number of MTRR descriptors to store.

◆ PAGE_ATTRIB_EXEC

#define PAGE_ATTRIB_EXEC   0x8

◆ PAGE_ATTRIB_EXEC_HIDDEN_HOOK

#define PAGE_ATTRIB_EXEC_HIDDEN_HOOK   0x10

◆ PAGE_ATTRIB_READ

#define PAGE_ATTRIB_READ   0x2

Page attributes for internal use.

◆ PAGE_ATTRIB_WRITE

#define PAGE_ATTRIB_WRITE   0x4

◆ SIZE_1_GB

#define SIZE_1_GB   ((SIZE_T)(512 * SIZE_2_MB))

Integer 1GB.

◆ SIZE_2_MB

#define SIZE_2_MB   ((SIZE_T)(512 * PAGE_SIZE))

Integer 2MB.

◆ SIZE_512_GB

#define SIZE_512_GB   ((SIZE_T)(512 * SIZE_1_GB))

Integer 512GB.

Typedef Documentation

◆ EPT_STATE

typedef struct _EPT_STATE EPT_STATE

Main structure for saving the state of EPT among the project.

◆ IA32_MTRR_FIXED_RANGE_TYPE

◆ MTRR_RANGE_DESCRIPTOR

MTRR Descriptor.

◆ PEPT_STATE

typedef struct _EPT_STATE * PEPT_STATE

◆ PMTRR_RANGE_DESCRIPTOR

◆ PVMM_EPT_DYNAMIC_SPLIT

◆ VMM_EPT_DYNAMIC_SPLIT

Split 2MB granularity to 4 KB granularity.

Function Documentation

◆ EptAllocateAndCreateIdentityPageTable()

PVMM_EPT_PAGE_TABLE EptAllocateAndCreateIdentityPageTable ( VOID )

Allocates page maps and create identity page table.

Returns
PVMM_EPT_PAGE_TABLE identity map page-table
688{
689 PVMM_EPT_PAGE_TABLE PageTable;
690 EPT_PML3_POINTER PML3Template;
691 EPT_PML3_ENTRY PML3TemplateLarge;
692 EPT_PML2_ENTRY PML2EntryTemplate;
693 SIZE_T EntryGroupIndex;
694 SIZE_T EntryIndex;
695
696 //
697 // Allocate all paging structures as 4KB aligned pages
698 //
699
700 //
701 // Allocate address anywhere in the OS's memory space and
702 // zero out all entries to ensure all unused entries are marked Not Present
703 //
705
706 if (PageTable == NULL)
707 {
708 LogError("Err, failed to allocate memory for PageTable");
709 return NULL;
710 }
711
712 //
713 // Keep track of dynamic 2MB->4KB split metadata for this EPT table.
714 //
715 InitializeListHead(&PageTable->DynamicSplitList);
716
717 //
718 // Create the template for the first entry in the PML4
719 //
720 PageTable->PML4[0].ReadAccess = 1;
721 PageTable->PML4[0].WriteAccess = 1;
722 PageTable->PML4[0].ExecuteAccess = 1;
723
724 //
725 // Copy the template into each of the 512 PML4 entry slots
726 //
727 CpuStosQ((SIZE_T *)&PageTable->PML4[1], PageTable->PML4[0].AsUInt, VMM_EPT_PML4E_COUNT - 1);
728
729 for (int i = 0; i < VMM_EPT_PML4E_COUNT; i++)
730 {
731 if (i == 0)
732 {
733 //
734 // Mark the first 512GB PML4 entry as present, which allows us to manage up
735 // to 512GB of discrete paging structures and also set other reserved bits
736 //
737 PageTable->PML4[0].PageFrameNumber = (SIZE_T)VirtualAddressToPhysicalAddress(&PageTable->PML3[0]) / PAGE_SIZE;
738 }
739 else
740 {
741 PageTable->PML4[i].PageFrameNumber = (SIZE_T)VirtualAddressToPhysicalAddress(&PageTable->PML3_RSVD[i - 1][0]) / PAGE_SIZE;
742 }
743 }
744
745 //
746 // Now mark each 1GB PML3 entry as RWX and map each to their PML2 entry
747 //
748
749 //
750 // Ensure stack memory is cleared
751 //
752 PML3Template.AsUInt = 0;
753 PML3TemplateLarge.AsUInt = 0;
754
755 //
756 // Set up one 'template' RWX PML3 entry and copy it into each of the 512 PML3 entries
757 // Using the same method as SimpleVisor for copying each entry using intrinsics
758 //
759 PML3Template.ReadAccess = 1;
760 PML3Template.WriteAccess = 1;
761 PML3Template.ExecuteAccess = 1;
762
763 PML3TemplateLarge.LargePage = 1;
764 PML3TemplateLarge.ReadAccess = 1;
765 PML3TemplateLarge.WriteAccess = 1;
766 PML3TemplateLarge.ExecuteAccess = 1;
767 PML3TemplateLarge.MemoryType = MEMORY_TYPE_UNCACHEABLE;
768
769 //
770 // Copy the template into each of the 512 PML3 entry slots for the original entries
771 //
772 CpuStosQ((SIZE_T *)&PageTable->PML3[0], PML3Template.AsUInt, VMM_EPT_PML3E_COUNT);
773
774 //
775 // Copt the template into each of the 512 PML3 entry slots for the reserved entries
776 //
777 for (SIZE_T i = 0; i < VMM_EPT_PML4E_COUNT - 1; i++)
778 {
779 CpuStosQ((SIZE_T *)&PageTable->PML3_RSVD[i][0], PML3TemplateLarge.AsUInt, VMM_EPT_PML3E_COUNT);
780 }
781
782 //
783 // For each of the 512 PML3 entries
784 //
785 for (EntryIndex = 0; EntryIndex < VMM_EPT_PML3E_COUNT; EntryIndex++)
786 {
787 //
788 // Map the 1GB PML3 entry to 512 PML2 (2MB) entries to describe each large page
789 // NOTE: We do *not* manage any PML1 (4096 byte) entries and do not allocate them
790 //
791 PageTable->PML3[EntryIndex].PageFrameNumber = (SIZE_T)VirtualAddressToPhysicalAddress(&PageTable->PML2[EntryIndex][0]) / PAGE_SIZE;
792 }
793
794 //
795 // For each of the 512 PML3 reserved entries for reserved PML3 entries
796 //
797 for (SIZE_T i = 0; i < VMM_EPT_PML4E_COUNT - 1; i++)
798 {
799 for (SIZE_T j = 0; j < VMM_EPT_PML3E_COUNT; j++)
800 {
801 //
802 // Map the 1GB PML3 reserved entry to 512 PML3 (1GB) entries to describe each large page
803 // NOTE: We do *not* manage them since they are reserved for out of 512 GB MMIO ranges
804 // The first 512GB is used for the main system memory and the rest is reserved for MMIO
805 //
806 PageTable->PML3_RSVD[i][j].PageFrameNumber = (SIZE_512_GB + // First 512GB is used for system memory
807 (i * SIZE_512_GB) + (j * SIZE_1_GB)) >> // MMIO ranges
808 30; // Convert to page frame number
809 }
810 }
811
812 //
813 // Now we will set up the PML2 entries, which are 2MB large pages
814 //
815 PML2EntryTemplate.AsUInt = 0;
816
817 //
818 // All PML2 entries will be RWX and 'present'
819 //
820 PML2EntryTemplate.WriteAccess = 1;
821 PML2EntryTemplate.ReadAccess = 1;
822 PML2EntryTemplate.ExecuteAccess = 1;
823
824 //
825 // We are using 2MB large pages, so we must mark this 1 here
826 //
827 PML2EntryTemplate.LargePage = 1;
828
829 //
830 // For each collection of 512 PML2 entries (512 collections * 512 entries per collection),
831 // mark it RWX using the same template above.
832 // This marks the entries as "Present" regardless of if the actual system has memory at
833 // this region or not. We will cause a fault in our EPT handler if the guest access a page
834 // outside a usable range, despite the EPT frame being present here
835 //
836 CpuStosQ((SIZE_T *)&PageTable->PML2[0], PML2EntryTemplate.AsUInt, VMM_EPT_PML3E_COUNT * VMM_EPT_PML2E_COUNT);
837
838 //
839 // For each of the 512 collections of 512 2MB PML2 entries
840 //
841 for (EntryGroupIndex = 0; EntryGroupIndex < VMM_EPT_PML3E_COUNT; EntryGroupIndex++)
842 {
843 //
844 // For each 2MB PML2 entry in the collection
845 //
846 for (EntryIndex = 0; EntryIndex < VMM_EPT_PML2E_COUNT; EntryIndex++)
847 {
848 //
849 // Setup the memory type and frame number of the PML2 entry
850 //
851 EptSetupPML2Entry(PageTable, &PageTable->PML2[EntryGroupIndex][EntryIndex], (EntryGroupIndex * VMM_EPT_PML2E_COUNT) + EntryIndex);
852 }
853 }
854
855 return PageTable;
856}
BOOLEAN EptSetupPML2Entry(PVMM_EPT_PAGE_TABLE EptPageTable, PEPT_PML2_ENTRY NewEntry, SIZE_T PageFrameNumber)
Set up PML2 Entries.
Definition Ept.c:655
#define SIZE_512_GB
Integer 512GB.
Definition Ept.h:43
#define SIZE_1_GB
Integer 1GB.
Definition Ept.h:37
VOID CpuStosQ(UINT64 *Destination, UINT64 Value, SIZE_T Count)
Store UINT64 value to memory Count times.
Definition PlatformIntrinsics.c:463
PVOID PlatformMemAllocateContiguousZeroedMemory(SIZE_T NumberOfBytes)
... Backward Compatibility / Specific APIs ...
Definition PlatformMem.c:184
#define LogError(format,...)
Log in the case of error.
Definition HyperDbgHyperLogIntrinsics.h:113
IMPORT_EXPORT_VMM UINT64 VirtualAddressToPhysicalAddress(_In_ PVOID VirtualAddress)
Converts Virtual Address to Physical Address.
Definition Conversion.c:154
struct _VMM_EPT_PAGE_TABLE VMM_EPT_PAGE_TABLE
Structure for saving EPT Table.
#define VMM_EPT_PML4E_COUNT
The number of 512GB PML4 entries in the page table.
Definition State.h:79
#define VMM_EPT_PML3E_COUNT
The number of 1GB PDPT entries in the page table per 512GB PML4 entry.
Definition State.h:85
#define VMM_EPT_PML2E_COUNT
Then number of 2MB Page Directory entries in the page table per 1GB PML3 entry.
Definition State.h:92
struct _VMM_EPT_PAGE_TABLE * PVMM_EPT_PAGE_TABLE
EPT_PDPTE EPT_PML3_POINTER
Definition State.h:19
EPT_PDPTE_1GB EPT_PML3_ENTRY
Definition State.h:20
EPT_PDE_2MB EPT_PML2_ENTRY
Definition State.h:21
#define PAGE_SIZE
Size of each page (4096 bytes).
Definition common.h:80
NULL()
Definition test-case-generator.py:530
EPT_PML4_POINTER PML4[VMM_EPT_PML4E_COUNT]
28.2.2 Describes 512 contiguous 512GB memory regions each with 512 1GB regions.
Definition State.h:111
EPT_PML3_POINTER PML3[VMM_EPT_PML3E_COUNT]
Describes exactly 512 contiguous 1GB memory regions within a our singular 512GB PML4 region.
Definition State.h:125
LIST_ENTRY DynamicSplitList
Tracks dynamic 2MB->4KB splits for this EPT table. NOTE: Each item stores a direct VA to the split PM...
Definition State.h:140
EPT_PML2_ENTRY PML2[VMM_EPT_PML3E_COUNT][VMM_EPT_PML2E_COUNT]
For each 1GB PML3 entry, create 512 2MB entries to map identity. NOTE: We are using 2MB pages as the ...
Definition State.h:133
EPT_PML3_ENTRY PML3_RSVD[VMM_EPT_PML4E_COUNT - 1][VMM_EPT_PML3E_COUNT]
Describes exactly 512 contiguous 1GB memory regions within a our singular 512GB PML4 region (This ent...
Definition State.h:119

◆ EptBuildMtrrMap()

BOOLEAN EptBuildMtrrMap ( VOID )

Build MTRR Map.

Build MTRR Map of current physical addresses.

Returns
BOOLEAN

Build MTRR Map.

Returns
BOOLEAN
168{
169 IA32_MTRR_CAPABILITIES_REGISTER MTRRCap;
170 IA32_MTRR_PHYSBASE_REGISTER CurrentPhysBase;
171 IA32_MTRR_PHYSMASK_REGISTER CurrentPhysMask;
172 IA32_MTRR_DEF_TYPE_REGISTER MTRRDefType;
173 PMTRR_RANGE_DESCRIPTOR Descriptor;
174 UINT32 CurrentRegister;
175 UINT32 NumberOfBitsInMask;
176
177 MTRRCap.AsUInt = CpuReadMsr(IA32_MTRR_CAPABILITIES);
178 MTRRDefType.AsUInt = CpuReadMsr(IA32_MTRR_DEF_TYPE);
179
180 //
181 // All MTRRs are disabled when clear, and the
182 // UC memory type is applied to all of physical memory.
183 //
184 if (!MTRRDefType.MtrrEnable)
185 {
186 g_EptState->DefaultMemoryType = MEMORY_TYPE_UNCACHEABLE;
187 return TRUE;
188 }
189
190 //
191 // The IA32_MTRR_DEF_TYPE MSR (named MTRRdefType MSR for the P6 family processors) sets the default
192 // properties of the regions of physical memory that are not encompassed by MTRRs
193 //
194 g_EptState->DefaultMemoryType = (UINT8)MTRRDefType.DefaultMemoryType;
195
196 //
197 // The fixed memory ranges are mapped with 11 fixed-range registers of 64 bits each. Each of these registers is
198 // divided into 8-bit fields that are used to specify the memory type for each of the sub-ranges the register controls:
199 // - Register IA32_MTRR_FIX64K_00000 - Maps the 512-KByte address range from 0H to 7FFFFH. This range
200 // is divided into eight 64-KByte sub-ranges.
201 //
202 // - Registers IA32_MTRR_FIX16K_80000 and IA32_MTRR_FIX16K_A0000 - Maps the two 128-KByte
203 // address ranges from 80000H to BFFFFH. This range is divided into sixteen 16-KByte sub-ranges, 8 ranges per
204 // register.
205 //
206 // - Registers IA32_MTRR_FIX4K_C0000 through IA32_MTRR_FIX4K_F8000 - Maps eight 32-KByte
207 // address ranges from C0000H to FFFFFH. This range is divided into sixty-four 4-KByte sub-ranges, 8 ranges per
208 // register.
209 //
210 if (MTRRCap.FixedRangeSupported && MTRRDefType.FixedRangeMtrrEnable)
211 {
212 const UINT32 K64Base = 0x0;
213 const UINT32 K64Size = 0x10000;
214 IA32_MTRR_FIXED_RANGE_TYPE K64Types = {CpuReadMsr(IA32_MTRR_FIX64K_00000)};
215 for (UINT32 i = 0; i < 8; i++)
216 {
217 Descriptor = &g_EptState->MemoryRanges[g_EptState->NumberOfEnabledMemoryRanges++];
218 Descriptor->MemoryType = K64Types.s.Types[i];
219 Descriptor->PhysicalBaseAddress = K64Base + (K64Size * i);
220 Descriptor->PhysicalEndAddress = K64Base + (K64Size * i) + (K64Size - 1);
221 Descriptor->FixedRange = TRUE;
222 }
223
224 const UINT32 K16Base = 0x80000;
225 const UINT32 K16Size = 0x4000;
226 for (UINT32 i = 0; i < 2; i++)
227 {
228 IA32_MTRR_FIXED_RANGE_TYPE K16Types = {CpuReadMsr(IA32_MTRR_FIX16K_80000 + i)};
229 for (UINT32 j = 0; j < 8; j++)
230 {
231 Descriptor = &g_EptState->MemoryRanges[g_EptState->NumberOfEnabledMemoryRanges++];
232 Descriptor->MemoryType = K16Types.s.Types[j];
233 Descriptor->PhysicalBaseAddress = (K16Base + (i * K16Size * 8)) + (K16Size * j);
234 Descriptor->PhysicalEndAddress = (K16Base + (i * K16Size * 8)) + (K16Size * j) + (K16Size - 1);
235 Descriptor->FixedRange = TRUE;
236 }
237 }
238
239 const UINT32 K4Base = 0xC0000;
240 const UINT32 K4Size = 0x1000;
241 for (UINT32 i = 0; i < 8; i++)
242 {
243 IA32_MTRR_FIXED_RANGE_TYPE K4Types = {CpuReadMsr(IA32_MTRR_FIX4K_C0000 + i)};
244
245 for (UINT32 j = 0; j < 8; j++)
246 {
247 Descriptor = &g_EptState->MemoryRanges[g_EptState->NumberOfEnabledMemoryRanges++];
248 Descriptor->MemoryType = K4Types.s.Types[j];
249 Descriptor->PhysicalBaseAddress = (K4Base + (i * K4Size * 8)) + (K4Size * j);
250 Descriptor->PhysicalEndAddress = (K4Base + (i * K4Size * 8)) + (K4Size * j) + (K4Size - 1);
251 Descriptor->FixedRange = TRUE;
252 }
253 }
254 }
255
256 for (CurrentRegister = 0; CurrentRegister < MTRRCap.VariableRangeCount; CurrentRegister++)
257 {
258 //
259 // For each dynamic register pair
260 //
261 CurrentPhysBase.AsUInt = CpuReadMsr(IA32_MTRR_PHYSBASE0 + (CurrentRegister * 2));
262 CurrentPhysMask.AsUInt = CpuReadMsr(IA32_MTRR_PHYSMASK0 + (CurrentRegister * 2));
263
264 //
265 // Is the range enabled?
266 //
267 if (CurrentPhysMask.Valid)
268 {
269 //
270 // We only need to read these once because the ISA dictates that MTRRs are
271 // to be synchronized between all processors during BIOS initialization.
272 //
273 Descriptor = &g_EptState->MemoryRanges[g_EptState->NumberOfEnabledMemoryRanges++];
274
275 //
276 // Calculate the base address in bytes
277 //
278 Descriptor->PhysicalBaseAddress = CurrentPhysBase.PageFrameNumber * PAGE_SIZE;
279
280 //
281 // Calculate the total size of the range
282 // The lowest bit of the mask that is set to 1 specifies the size of the range
283 //
284 CpuBitScanForward64((ULONG *)&NumberOfBitsInMask, CurrentPhysMask.PageFrameNumber * PAGE_SIZE);
285
286 //
287 // Size of the range in bytes + Base Address
288 //
289 Descriptor->PhysicalEndAddress = Descriptor->PhysicalBaseAddress + ((1ULL << NumberOfBitsInMask) - 1ULL);
290
291 //
292 // Memory Type (cacheability attributes)
293 //
294 Descriptor->MemoryType = (UCHAR)CurrentPhysBase.Type;
295
296 Descriptor->FixedRange = FALSE;
297
298 LogDebugInfo("MTRR Range: Base=0x%llx End=0x%llx Type=0x%x", Descriptor->PhysicalBaseAddress, Descriptor->PhysicalEndAddress, Descriptor->MemoryType);
299 }
300 }
301
302 LogDebugInfo("Total MTRR ranges committed: 0x%x", g_EptState->NumberOfEnabledMemoryRanges);
303
304 return TRUE;
305}
struct _MTRR_RANGE_DESCRIPTOR * PMTRR_RANGE_DESCRIPTOR
union _IA32_MTRR_FIXED_RANGE_TYPE IA32_MTRR_FIXED_RANGE_TYPE
Fixed range MTRR.
UCHAR CpuBitScanForward64(ULONG *Index, UINT64 Mask)
Bit scan forward (64-bit).
Definition PlatformIntrinsics.c:486
UINT64 CpuReadMsr(ULONG MsrAddress)
Read an MSR.
Definition PlatformIntrinsics.c:213
unsigned char UCHAR
Definition BasicTypes.h:34
#define TRUE
Definition BasicTypes.h:114
#define FALSE
Definition BasicTypes.h:113
unsigned char UINT8
Definition BasicTypes.h:52
unsigned int UINT32
Definition BasicTypes.h:54
unsigned long ULONG
Definition BasicTypes.h:31
#define LogDebugInfo(format,...)
Log, initialize boot information and debug information.
Definition HyperDbgHyperLogIntrinsics.h:155
EPT_STATE * g_EptState
Save the state and variables related to EPT.
Definition GlobalVariables.h:50
UCHAR MemoryType
Definition Ept.h:87
BOOLEAN FixedRange
Definition Ept.h:88
SIZE_T PhysicalBaseAddress
Definition Ept.h:85
SIZE_T PhysicalEndAddress
Definition Ept.h:86
UINT8 Types[8]
Definition Ept.h:100
struct _IA32_MTRR_FIXED_RANGE_TYPE::@170207037044173377154145111113263372336161202124 s

◆ EptCheckAndHandleBreakpoint()

BOOLEAN EptCheckAndHandleBreakpoint ( VIRTUAL_MACHINE_STATE * VCpu)

Check if the breakpoint vm-exit relates to EPT hook or not.

Parameters
VCpuThe virtual processor's state
Returns
BOOLEAN
1318{
1319 UINT64 GuestRip = 0;
1320 BOOLEAN IsHandledByEptHook;
1321
1322 //
1323 // Reading guest's RIP
1324 //
1325 VmxVmread64P(VMCS_GUEST_RIP, &GuestRip);
1326
1327 //
1328 // Don't increment rip by default
1329 //
1331
1332 //
1333 // Check if it relates to !epthook or not
1334 //
1335 IsHandledByEptHook = EptCheckAndHandleEptHookBreakpoints(VCpu, GuestRip);
1336
1337 return IsHandledByEptHook;
1338}
BOOLEAN EptCheckAndHandleEptHookBreakpoints(VIRTUAL_MACHINE_STATE *VCpu, UINT64 GuestRip)
Perform checking and handling if the breakpoint vm-exit relates to EPT hook or not.
Definition Ept.c:1217
VOID HvSuppressRipIncrement(VIRTUAL_MACHINE_STATE *VCpu)
Suppress the incrementation of RIP.
Definition Hv.c:320
UCHAR VmxVmread64P(size_t Field, UINT64 *FieldValue)
VMX VMREAD instruction (64-bit, pointer variant).
Definition PlatformIntrinsicsVmx.c:207
UCHAR BOOLEAN
Definition BasicTypes.h:35

◆ EptCheckFeatures()

BOOLEAN EptCheckFeatures ( VOID )

Check for EPT Features.

Check whether EPT features are present or not.

Returns
BOOLEAN

Check for EPT Features.

Returns
BOOLEAN Shows whether EPT is supported in this machine or not
23{
24 IA32_VMX_EPT_VPID_CAP_REGISTER VpidRegister;
25 IA32_MTRR_DEF_TYPE_REGISTER MTRRDefType;
27 VpidRegister.AsUInt = CpuReadMsr(IA32_VMX_EPT_VPID_CAP);
28 MTRRDefType.AsUInt = CpuReadMsr(IA32_MTRR_DEF_TYPE);
29
30 if (!VpidRegister.PageWalkLength4 || !VpidRegister.MemoryTypeWriteBack || !VpidRegister.Pde2MbPages)
31 {
32 return FALSE;
33 }
34
35 if (!VpidRegister.AdvancedVmexitEptViolationsInformation)
36 {
37 LogDebugInfo("The processor doesn't report advanced VM-exit information for EPT violations");
38 }
39
40 if (VpidRegister.Invvpid &&
41 VpidRegister.InvvpidAllContexts &&
42 VpidRegister.InvvpidIndividualAddress &&
43 VpidRegister.InvvpidSingleContext &&
44 VpidRegister.InvvpidSingleContextRetainGlobals &&
46 {
48 LogDebugInfo("The processor supports VPID");
49 }
50
51 if (!VpidRegister.ExecuteOnlyPages)
52 {
53 g_CompatibilityCheck.ExecuteOnlySupport = FALSE;
54 LogDebugInfo("The processor doesn't support execute-only pages, execute hooks won't work as they're on this feature in our design");
55 }
56 else
57 {
58 g_CompatibilityCheck.ExecuteOnlySupport = TRUE;
59 }
60
61 if (!MTRRDefType.MtrrEnable)
62 {
63 LogError("Err, MTRR dynamic ranges are not supported");
64 return FALSE;
65 }
66
67 LogDebugInfo("All EPT features are present");
68
69 return TRUE;
70}
BOOLEAN g_IsVpidSupported
Whether VPID is supported or not.
Definition GlobalVariables.h:215
BOOLEAN g_IsTopLevelHypervisorHyperV
Whether the top level hypervisor is Hyper-V or not.
Definition GlobalVariables.h:220
COMPATIBILITY_CHECKS_STATUS g_CompatibilityCheck
Different attributes and compatibility checks of the current processor.
Definition GlobalVariables.h:26

◆ EptGetPml1Entry()

PEPT_PML1_ENTRY EptGetPml1Entry ( PVMM_EPT_PAGE_TABLE EptPageTable,
SIZE_T PhysicalAddress )

Get the PML1 Entry of a special address.

Get the PML1 entry for this physical address if the page is split.

Parameters
EptPageTable
PhysicalAddress
Returns
PEPT_PML1_ENTRY

Get the PML1 Entry of a special address.

Parameters
EptPageTableThe EPT Page Table
PhysicalAddressPhysical address that we want to get its PML1
Returns
PEPT_PML1_ENTRY Return NULL if the address is invalid or the page wasn't already split
338{
339 SIZE_T Directory, DirectoryPointer, PML4Entry;
340 PEPT_PML2_ENTRY PML2;
341 PEPT_PML1_ENTRY PML1;
342
343 Directory = ADDRMASK_EPT_PML2_INDEX(PhysicalAddress);
344 DirectoryPointer = ADDRMASK_EPT_PML3_INDEX(PhysicalAddress);
345 PML4Entry = ADDRMASK_EPT_PML4_INDEX(PhysicalAddress);
346
347 //
348 // Addresses above 512GB are invalid because it is > physical address bus width
349 //
350 if (PML4Entry > 0)
351 {
352 return NULL;
353 }
354
355 PML2 = &EptPageTable->PML2[DirectoryPointer][Directory];
356
357 //
358 // Check to ensure the page is split
359 //
360 if (PML2->LargePage)
361 {
362 return NULL;
363 }
364
365 //
366 // Resolve the split PML1 VA that was recorded during EptSplitLargePage
367 //
368 PML1 = EptGetSplitPml1VaByPml2Entry(EptPageTable, PML2);
369
370 if (!PML1)
371 {
372 return NULL;
373 }
374
375 //
376 // Index into PML1 for that address
377 //
378 PML1 = &PML1[ADDRMASK_EPT_PML1_INDEX(PhysicalAddress)];
379
380 return PML1;
381}
#define ADDRMASK_EPT_PML2_INDEX(_VAR_)
Index of the 2nd paging structure (2MB).
Definition Ept.h:61
#define ADDRMASK_EPT_PML4_INDEX(_VAR_)
Index of the 4th paging structure (512GB).
Definition Ept.h:73
#define ADDRMASK_EPT_PML1_INDEX(_VAR_)
Index of the 1st paging structure (4096 byte).
Definition Ept.h:55
#define ADDRMASK_EPT_PML3_INDEX(_VAR_)
Index of the 3rd paging structure (1GB).
Definition Ept.h:67
EPT_PTE * PEPT_PML1_ENTRY
Definition State.h:23
EPT_PDE_2MB * PEPT_PML2_ENTRY
Definition State.h:21

◆ EptGetPml1OrPml2Entry()

PVOID EptGetPml1OrPml2Entry ( PVMM_EPT_PAGE_TABLE EptPageTable,
SIZE_T PhysicalAddress,
BOOLEAN * IsLargePage )

Get the PML1 entry for this physical address if the large page is available then large page of Pml2 is returned.

Parameters
EptPageTableThe EPT Page Table
PhysicalAddressPhysical address that we want to get its PML1
IsLargePageShows whether it's a large page or not
Returns
PEPT_PML1_ENTRY Return PEPT_PML1_ENTRY or PEPT_PML2_ENTRY
Parameters
EptPageTableThe EPT Page Table
PhysicalAddressPhysical address that we want to get its PML1
IsLargePageShows whether it's a large page or not
Returns
PVOID Return PEPT_PML1_ENTRY or PEPT_PML2_ENTRY
395{
396 SIZE_T Directory, DirectoryPointer, PML4Entry;
397 PEPT_PML2_ENTRY PML2;
398 PEPT_PML1_ENTRY PML1;
399
400 Directory = ADDRMASK_EPT_PML2_INDEX(PhysicalAddress);
401 DirectoryPointer = ADDRMASK_EPT_PML3_INDEX(PhysicalAddress);
402 PML4Entry = ADDRMASK_EPT_PML4_INDEX(PhysicalAddress);
403
404 //
405 // Addresses above 512GB are invalid because it is > physical address bus width
406 //
407 if (PML4Entry > 0)
408 {
409 return NULL;
410 }
411
412 PML2 = &EptPageTable->PML2[DirectoryPointer][Directory];
413
414 //
415 // Check to ensure the page is split
416 //
417 if (PML2->LargePage)
418 {
419 *IsLargePage = TRUE;
420 return PML2;
421 }
422
423 //
424 // Resolve the split PML1 VA that was recorded during EptSplitLargePage
425 //
426 PML1 = EptGetSplitPml1VaByPml2Entry(EptPageTable, PML2);
427
428 if (!PML1)
429 {
430 return NULL;
431 }
432
433 //
434 // Index into PML1 for that address
435 //
436 PML1 = &PML1[ADDRMASK_EPT_PML1_INDEX(PhysicalAddress)];
437
438 *IsLargePage = FALSE;
439 return PML1;
440}

◆ EptGetPml2Entry()

PEPT_PML2_ENTRY EptGetPml2Entry ( PVMM_EPT_PAGE_TABLE EptPageTable,
SIZE_T PhysicalAddress )

Split 2MB (LargePage) into 4kb pages.

Get the PML2 entry for this physical address.

Parameters
EptPageTableThe EPT Page Table
PreAllocatedBufferThe address of pre-allocated buffer
PhysicalAddressPhysical address of where we want to split
Returns
BOOLEAN Returns true if it was successful or false if there was an error

Split 2MB (LargePage) into 4kb pages.

Parameters
EptPageTableThe EPT Page Table
PhysicalAddressPhysical Address that we want to get its PML2
Returns
PEPT_PML2_ENTRY The PML2 Entry Structure
451{
452 SIZE_T Directory, DirectoryPointer, PML4Entry;
453 PEPT_PML2_ENTRY PML2;
454
455 Directory = ADDRMASK_EPT_PML2_INDEX(PhysicalAddress);
456 DirectoryPointer = ADDRMASK_EPT_PML3_INDEX(PhysicalAddress);
457 PML4Entry = ADDRMASK_EPT_PML4_INDEX(PhysicalAddress);
458
459 //
460 // Addresses above 512GB are invalid because it is > physical address bus width
461 //
462 if (PML4Entry > 0)
463 {
464 return NULL;
465 }
466
467 PML2 = &EptPageTable->PML2[DirectoryPointer][Directory];
468 return PML2;
469}

◆ EptHandleEptViolation()

BOOLEAN EptHandleEptViolation ( VIRTUAL_MACHINE_STATE * VCpu)

Handle EPT Violation.

Handle VM exits for EPT violations.

Parameters
VCpuThe virtual processor's state
Returns
BOOLEAN

Handle EPT Violation.

Violations are thrown whenever an operation is performed on an EPT entry that does not provide permissions to access that page

Parameters
VCpuThe virtual processor's state
Returns
BOOLEAN Return true if the violation was handled by the page hook handler and false if it was not handled
1109{
1110 UINT64 GuestPhysicalAddr;
1111 VMX_EXIT_QUALIFICATION_EPT_VIOLATION ViolationQualification = {.AsUInt = VCpu->ExitQualification};
1112
1113 //
1114 // Reading guest physical address
1115 //
1116 VmxVmread64P(VMCS_GUEST_PHYSICAL_ADDRESS, &GuestPhysicalAddr);
1117
1118 if (EptHandlePageHookExit(VCpu, ViolationQualification, GuestPhysicalAddr))
1119 {
1120 //
1121 // Handled by page hook code
1122 //
1123 return TRUE;
1124 }
1125 else if (ExecTrapHandleEptViolationVmexit(VCpu, &ViolationQualification))
1126 {
1127 return TRUE;
1128 }
1129 else if (VmmCallbackUnhandledEptViolation(VCpu->CoreId, (UINT64)ViolationQualification.AsUInt, GuestPhysicalAddr))
1130 {
1131 //
1132 // Check whether this violation is meaningful for the application or not
1133 //
1134 return TRUE;
1135 }
1136
1137 LogError("Err, unexpected EPT violation at RIP: %llx", VCpu->LastVmexitRip);
1138 DbgBreakPoint();
1139 //
1140 // Redo the instruction that caused the exception
1141 //
1142 return FALSE;
1143}
BOOLEAN VmmCallbackUnhandledEptViolation(UINT32 CoreId, UINT64 ViolationQualification, UINT64 GuestPhysicalAddr)
routine callback to handle unhandled EPT violations
Definition Callback.c:167
_Use_decl_annotations_ BOOLEAN EptHandlePageHookExit(VIRTUAL_MACHINE_STATE *VCpu, VMX_EXIT_QUALIFICATION_EPT_VIOLATION ViolationQualification, UINT64 GuestPhysicalAddr)
Check if this exit is due to a violation caused by a currently hooked page.
Definition Ept.c:950
BOOLEAN ExecTrapHandleEptViolationVmexit(VIRTUAL_MACHINE_STATE *VCpu, VMX_EXIT_QUALIFICATION_EPT_VIOLATION *ViolationQualification)
Handle EPT Violations related to the MBEC hooks.
Definition ExecTrap.c:655
UINT32 ExitQualification
Definition State.h:330
UINT32 CoreId
Definition State.h:328
UINT64 LastVmexitRip
Definition State.h:331

◆ EptHandleMisconfiguration()

VOID EptHandleMisconfiguration ( VOID )

Handle Ept Misconfigurations.

Handle vm-exits for EPT Misconfiguration.

Returns
VOID

Handle Ept Misconfigurations.

Parameters
GuestAddress
Returns
VOID
1153{
1154 UINT64 GuestPhysicalAddr = 0;
1155
1156 VmxVmread64P(VMCS_GUEST_PHYSICAL_ADDRESS, &GuestPhysicalAddr);
1157
1158 LogInfo("EPT Misconfiguration!");
1159
1160 LogError("Err, a field in the EPT paging structure was invalid, faulting guest address : 0x%llx",
1161 GuestPhysicalAddr);
1162
1163 //
1164 // We can't continue now.
1165 // EPT misconfiguration is a fatal exception that will probably crash the OS if we don't get out now
1166 //
1167}
#define LogInfo(format,...)
Define log variables.
Definition HyperDbgHyperLogIntrinsics.h:71

◆ EptHandlePageHookExit()

BOOLEAN EptHandlePageHookExit ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu,
_In_ VMX_EXIT_QUALIFICATION_EPT_VIOLATION ViolationQualification,
_In_ UINT64 GuestPhysicalAddr )

◆ EptLogicalProcessorInitialize()

BOOLEAN EptLogicalProcessorInitialize ( VOID )

Initialize EPT Table based on Processor Index.

Initialize EPT for an individual logical processor.

Returns
BOOLEAN

Initialize EPT Table based on Processor Index.

Creates an identity mapped page table and sets up an EPTP to be applied to the VMCS later

Returns
BOOLEAN
866{
867 ULONG ProcessorsCount;
868 PVMM_EPT_PAGE_TABLE PageTable;
869 EPT_POINTER EPTP = {0};
870
871 //
872 // Get number of processors
873 //
874 ProcessorsCount = KeQueryActiveProcessorCount(0);
875
876 for (SIZE_T i = 0; i < ProcessorsCount; i++)
877 {
878 //
879 // Allocate the identity mapped page table
880 //
882
883 if (!PageTable)
884 {
885 //
886 // Try to deallocate previous pools (if any)
887 //
888 for (SIZE_T j = 0; j < ProcessorsCount; j++)
889 {
890 if (g_GuestState[j].EptPageTable != NULL)
891 {
892 MmFreeContiguousMemory(g_GuestState[j].EptPageTable);
893 g_GuestState[j].EptPageTable = NULL;
894 }
895 }
896
897 LogError("Err, unable to allocate memory for EPT");
898 return FALSE;
899 }
900
901 //
902 // Virtual address to the page table to keep track of it for later freeing
903 //
904 g_GuestState[i].EptPageTable = PageTable;
905
906 //
907 // Use default memory type
908 //
909 EPTP.MemoryType = g_EptState->DefaultMemoryType;
910
911 //
912 // We might utilize the 'access' and 'dirty' flag features in the dirty logging mechanism
913 //
914 EPTP.EnableAccessAndDirtyFlags = TRUE;
915
916 //
917 // Bits 5:3 (1 less than the EPT page-walk length) must be 3, indicating an EPT page-walk length of 4;
918 // see Section 28.2.2
919 //
920 EPTP.PageWalkLength = 3;
921
922 //
923 // The physical page number of the page table we will be using
924 //
925 EPTP.PageFrameNumber = (SIZE_T)VirtualAddressToPhysicalAddress(&PageTable->PML4) / PAGE_SIZE;
926
927 //
928 // We will write the EPTP to the VMCS later
929 //
930 g_GuestState[i].EptPointer = EPTP;
931 }
932
933 return TRUE;
934}
PVMM_EPT_PAGE_TABLE EptAllocateAndCreateIdentityPageTable(VOID)
Allocates page maps and create identity page table.
Definition Ept.c:687
VIRTUAL_MACHINE_STATE * g_GuestState
Save the state and variables related to virtualization on each to logical core.
Definition GlobalVariables.h:38

◆ EptSetPML1AndInvalidateTLB()

VOID EptSetPML1AndInvalidateTLB ( _Inout_ VIRTUAL_MACHINE_STATE * VCpu,
_Out_ PEPT_PML1_ENTRY EntryAddress,
_In_ EPT_PML1_ENTRY EntryValue,
_In_ _Strict_type_match_ INVEPT_TYPE InvalidationType )

This function set the specific PML1 entry in a spinlock protected area then invalidate the TLB , this function should be called from vmx root-mode.

Parameters
EntryAddress
EntryValue
InvalidationType
Returns
VOID

◆ EptSetupPML2Entry()

BOOLEAN EptSetupPML2Entry ( PVMM_EPT_PAGE_TABLE EptPageTable,
PEPT_PML2_ENTRY NewEntry,
SIZE_T PageFrameNumber )

Set up PML2 Entries.

Parameters
EptPageTable
NewEntryThe PML2 Entry
PageFrameNumberPFN (Physical Address)
Returns
VOID
656{
657 //
658 // Each of the 512 collections of 512 PML2 entries is setup here
659 // This will, in total, identity map every physical address from 0x0
660 // to physical address 0x8000000000 (512GB of memory)
661 // ((EntryGroupIndex * VMM_EPT_PML2E_COUNT) + EntryIndex) * 2MB is
662 // the actual physical address we're mapping
663 //
664 NewEntry->PageFrameNumber = PageFrameNumber;
665
666 if (EptIsValidForLargePage(PageFrameNumber))
667 {
668 NewEntry->MemoryType = EptGetMemoryType(PageFrameNumber, TRUE);
669
670 return TRUE;
671 }
672 else
673 {
674 //
675 // Here we won't need to use pre-allocated buffers
676 //
677 return EptSplitLargePage(EptPageTable, FALSE, PageFrameNumber * SIZE_2_MB);
678 }
679}
BOOLEAN EptIsValidForLargePage(SIZE_T PageFrameNumber)
Check if potential large page doesn't land on two or more different cache memory types.
Definition Ept.c:623
BOOLEAN EptSplitLargePage(PVMM_EPT_PAGE_TABLE EptPageTable, BOOLEAN UsePreAllocatedBuffer, SIZE_T PhysicalAddress)
Convert large pages to 4KB pages.
Definition Ept.c:481
UINT8 EptGetMemoryType(SIZE_T PageFrameNumber, BOOLEAN IsLargePage)
Check whether EPT features are present or not.
Definition Ept.c:80
#define SIZE_2_MB
Integer 2MB.
Definition Ept.h:31

◆ EptSplitLargePage()

BOOLEAN EptSplitLargePage ( PVMM_EPT_PAGE_TABLE EptPageTable,
BOOLEAN UsePreAllocatedBuffer,
SIZE_T PhysicalAddress )

Convert large pages to 4KB pages.

Parameters
EptPageTable
UsePreAllocatedBuffer
PhysicalAddress
Returns
BOOLEAN
Parameters
EptPageTableThe EPT Page Table
UsePreAllocatedBufferWhether allocate a memory or use pre-allocated buffer
PhysicalAddressPhysical address of where we want to split
Returns
BOOLEAN Returns true if it was successful or false if there was an error
484{
485 PVMM_EPT_DYNAMIC_SPLIT NewSplit;
486 EPT_PML1_ENTRY EntryTemplate;
487 SIZE_T EntryIndex;
488 PEPT_PML2_ENTRY TargetEntry;
489 EPT_PML2_POINTER NewPointer;
490
491 //
492 // Find the PML2 entry that's currently used
493 //
494 TargetEntry = EptGetPml2Entry(EptPageTable, PhysicalAddress);
495
496 if (!TargetEntry)
497 {
498 LogError("Err, an invalid physical address passed");
499 return FALSE;
500 }
501
502 //
503 // If this large page is not marked a large page, that means it's a pointer already.
504 // That page is therefore already split.
505 //
506 if (!TargetEntry->LargePage)
507 {
508 return TRUE;
509 }
510
511 //
512 // Allocate the PML1 entries
513 //
514 if (UsePreAllocatedBuffer)
515 {
517 }
518 else
519 {
521 }
522
523 if (!NewSplit)
524 {
525 LogError("Err, failed to allocate dynamic split memory");
526 return FALSE;
527 }
528 RtlZeroMemory(NewSplit, sizeof(VMM_EPT_DYNAMIC_SPLIT));
529
530 //
531 // Point back to the entry in the dynamic split for easy reference for which entry that
532 // dynamic split is for
533 //
534 NewSplit->Fields.Entry = TargetEntry;
535
536 //
537 // Make a template for RWX
538 //
539 EntryTemplate.AsUInt = 0;
540 EntryTemplate.ReadAccess = 1;
541 EntryTemplate.WriteAccess = 1;
542 EntryTemplate.ExecuteAccess = 1;
543
544 //
545 // Set the UserModeExecute bit based on the global state of MBEC
546 //
548 {
549 EntryTemplate.UserModeExecute = 1;
550 }
551 else
552 {
553 EntryTemplate.UserModeExecute = 0;
554 }
555
556 //
557 // copy other bits from target entry
558 //
559 EntryTemplate.MemoryType = TargetEntry->MemoryType;
560 EntryTemplate.IgnorePat = TargetEntry->IgnorePat;
561 EntryTemplate.SuppressVe = TargetEntry->SuppressVe;
562
563 //
564 // Copy the template into all the PML1 entries
565 //
566 CpuStosQ((SIZE_T *)&NewSplit->PML1[0], EntryTemplate.AsUInt, VMM_EPT_PML1E_COUNT);
567
568 //
569 // Set the page frame numbers for identity mapping
570 //
571 for (EntryIndex = 0; EntryIndex < VMM_EPT_PML1E_COUNT; EntryIndex++)
572 {
573 //
574 // Convert the 2MB page frame number to the 4096 page entry number plus the offset into the frame
575 //
576 NewSplit->PML1[EntryIndex].PageFrameNumber = ((TargetEntry->PageFrameNumber * SIZE_2_MB) / PAGE_SIZE) + EntryIndex;
577 NewSplit->PML1[EntryIndex].MemoryType = EptGetMemoryType(NewSplit->PML1[EntryIndex].PageFrameNumber, FALSE);
578 }
579
580 //
581 // Allocate a new pointer which will replace the 2MB entry with a pointer to 512 4096 byte entries
582 //
583 NewPointer.AsUInt = 0;
584 NewPointer.WriteAccess = 1;
585 NewPointer.ReadAccess = 1;
586 NewPointer.ExecuteAccess = 1;
587
588 //
589 // Set the UserModeExecute bit based on the global state of MBEC
590 //
592 {
593 NewPointer.UserModeExecute = 1;
594 }
595 else
596 {
597 NewPointer.UserModeExecute = 0;
598 }
599
600 NewPointer.PageFrameNumber = (SIZE_T)VirtualAddressToPhysicalAddress(&NewSplit->PML1[0]) / PAGE_SIZE;
601
602 //
603 // Now, replace the entry in the page table with our new split pointer
604 //
605 RtlCopyMemory(TargetEntry, &NewPointer, sizeof(NewPointer));
606
607 //
608 // Track the split so we can directly resolve PML1 VA from PML2 entry
609 // without any PA->VA reverse translation
610 //
611 InsertHeadList(&EptPageTable->DynamicSplitList, &(NewSplit->DynamicSplitList));
612
613 return TRUE;
614}
UINT64 PoolManagerCallbackRequestPool(POOL_ALLOCATION_INTENTION Intention, BOOLEAN RequestNewPool, UINT32 Size)
routine callback to request pool
Definition Callback.c:358
PEPT_PML2_ENTRY EptGetPml2Entry(PVMM_EPT_PAGE_TABLE EptPageTable, SIZE_T PhysicalAddress)
Get the PML2 entry for this physical address.
Definition Ept.c:450
struct _VMM_EPT_DYNAMIC_SPLIT * PVMM_EPT_DYNAMIC_SPLIT
struct _VMM_EPT_DYNAMIC_SPLIT VMM_EPT_DYNAMIC_SPLIT
Split 2MB granularity to 4 KB granularity.
PVOID PlatformMemAllocateNonPagedPool(SIZE_T NumberOfBytes)
Allocates non-paged pool memory.
Definition PlatformMem.c:208
@ SPLIT_2MB_PAGING_TO_4KB_PAGE
Definition DataTypes.h:76
EPT_PTE EPT_PML1_ENTRY
Definition State.h:23
EPT_PDE EPT_PML2_POINTER
Definition State.h:22
#define VMM_EPT_PML1E_COUNT
Then number of 4096 byte Page Table entries in the page table per 2MB PML2 entry when dynamically spl...
Definition State.h:99
BOOLEAN g_ModeBasedExecutionControlState
Enable interception of Cr3 for Mode-based Execution detection.
Definition GlobalVariables.h:106
LIST_ENTRY DynamicSplitList
Linked list entries for each dynamic split.
Definition Ept.h:163
EPT_PML1_ENTRY PML1[VMM_EPT_PML1E_COUNT]
The 4096 byte page table entries that correspond to the split 2MB table entry.
Definition Ept.h:147
PEPT_PML2_ENTRY Entry
Definition Ept.h:155
union _VMM_EPT_DYNAMIC_SPLIT::@275337017054050120003261225167376117025061264241 Fields
The pointer to the 2MB entry in the page table which this split is servicing.