set user mode execute bit for different core EPTPs

This commit is contained in:
sina 2025-07-08 00:10:43 +02:00
parent beed7ccc34
commit 0e5ff45c30
No known key found for this signature in database
6 changed files with 104 additions and 9 deletions

View file

@ -2570,7 +2570,7 @@ EptHookModifyInstructionFetchState(VIRTUAL_MACHINE_STATE * VCpu,
PVOID PmlEntry = NULL;
BOOLEAN IsLargePage = FALSE;
PmlEntry = EptGetPml1OrPml2Entry(g_EptState->EptPageTable, (SIZE_T)PhysicalAddress, &IsLargePage);
PmlEntry = EptGetPml1OrPml2Entry(VCpu->EptPageTable, (SIZE_T)PhysicalAddress, &IsLargePage);
if (PmlEntry)
{
@ -2628,7 +2628,7 @@ EptHookModifyPageReadState(VIRTUAL_MACHINE_STATE * VCpu,
PVOID PmlEntry = NULL;
BOOLEAN IsLargePage = FALSE;
PmlEntry = EptGetPml1OrPml2Entry(g_EptState->EptPageTable, (SIZE_T)PhysicalAddress, &IsLargePage);
PmlEntry = EptGetPml1OrPml2Entry(VCpu->EptPageTable, (SIZE_T)PhysicalAddress, &IsLargePage);
if (PmlEntry)
{
@ -2686,7 +2686,7 @@ EptHookModifyPageWriteState(VIRTUAL_MACHINE_STATE * VCpu,
PVOID PmlEntry = NULL;
BOOLEAN IsLargePage = FALSE;
PmlEntry = EptGetPml1OrPml2Entry(g_EptState->EptPageTable, (SIZE_T)PhysicalAddress, &IsLargePage);
PmlEntry = EptGetPml1OrPml2Entry(VCpu->EptPageTable, (SIZE_T)PhysicalAddress, &IsLargePage);
if (PmlEntry)
{

View file

@ -572,6 +572,47 @@ ExecTrapChangeToKernelDisabledMbecEptp(VIRTUAL_MACHINE_STATE * VCpu)
VCpu->NotNormalEptp = TRUE;
}
/**
* @brief change to normal MBEC EPTP
* @param VCpu The virtual processor's state
*
* @return VOID
*/
VOID
ExecTrapChangeToNormalMbecEptp(VIRTUAL_MACHINE_STATE * VCpu)
{
//
// From Intel Manual:
// [Bit 2] If the "mode-based execute control for EPT" VM - execution control is 0, execute access;
// indicates whether instruction fetches are allowed from the 2-MByte page controlled by this entry.
// If that control is 1, execute access for supervisor-mode linear addresses; indicates whether instruction
// fetches are allowed from supervisor - mode linear addresses in the 2 - MByte page controlled by this entry
//
//
// Set execute access for PML4s
//
// for (size_t i = 0; i < VMM_EPT_PML4E_COUNT; i++)
// {
VCpu->EptPageTable->PML4[0].UserModeExecute = TRUE;
//
// We only set the top-level PML4 for intercepting kernel-mode execution
//
VCpu->EptPageTable->PML4[0].ExecuteAccess = TRUE;
// }
//
// Invalidate the EPT cache
//
EptInveptSingleContext(VCpu->EptPointer.AsUInt);
//
// It's not on normal EPTP
//
VCpu->NotNormalEptp = FALSE;
}
/**
* @brief Restore the execution of the trap to adjusted trap state
* @param VCpu The virtual processor's state
@ -711,6 +752,7 @@ ExecTrapApplyMbecConfiguratinFromKernelSide(VIRTUAL_MACHINE_STATE * VCpu)
//
// Enable MBEC to detect execution in user-mode
//
ExecTrapChangeToNormalMbecEptp(VCpu);
HvSetModeBasedExecutionEnableFlag(TRUE);
VCpu->MbecEnabled = TRUE;
@ -724,6 +766,7 @@ ExecTrapApplyMbecConfiguratinFromKernelSide(VIRTUAL_MACHINE_STATE * VCpu)
//
// In case, the process is changed, we've disable the MBEC
//
ExecTrapChangeToNormalMbecEptp(VCpu);
HvSetModeBasedExecutionEnableFlag(FALSE);
VCpu->MbecEnabled = FALSE;
}

View file

@ -118,6 +118,8 @@ ModeBasedExecHookDisableKernelModeExecution(PVMM_EPT_PAGE_TABLE EptTable)
BOOLEAN
ModeBasedExecHookEnableUsermodeExecution(PVMM_EPT_PAGE_TABLE EptTable)
{
EPT_PML1_ENTRY Pml1Entries[VMM_EPT_PML1E_COUNT];
//
// Set execute access for PML4s
//
@ -145,6 +147,32 @@ ModeBasedExecHookEnableUsermodeExecution(PVMM_EPT_PAGE_TABLE EptTable)
for (size_t j = 0; j < VMM_EPT_PML2E_COUNT; j++)
{
EptTable->PML2[i][j].UserModeExecute = TRUE;
//
// If the PML2 entry is not a large page, we should set execute access for PML1s
// It usually happens when the PML2 entry is not a large page and is previously
// used for an EPT hook, so, it has PML1 entries
//
if (!EptTable->PML2[i][j].LargePage)
{
//
// Shift to the left to get the PFN
//
MemoryMapperReadMemorySafeByPhysicalAddress(EptTable->PML2[i][j].PageFrameNumber << 12, (UINT64)Pml1Entries, PAGE_SIZE);
//
// Set execute access for PML1s
//
for (size_t k = 0; k < VMM_EPT_PML1E_COUNT; k++)
{
Pml1Entries[k].UserModeExecute = TRUE;
}
//
// Write back the PML1 entries to the EPT page table
//
MemoryMapperWriteMemorySafeByPhysicalAddress(EptTable->PML2[i][j].PageFrameNumber << 12, (UINT64)Pml1Entries, PAGE_SIZE);
}
}
}

View file

@ -520,6 +520,18 @@ EptSplitLargePage(PVMM_EPT_PAGE_TABLE EptPageTable,
EntryTemplate.WriteAccess = 1;
EntryTemplate.ExecuteAccess = 1;
//
// Set the UserModeExecute bit based on the global state of MBEC
//
if (g_ModeBasedExecutionControlState)
{
EntryTemplate.UserModeExecute = 1;
}
else
{
EntryTemplate.UserModeExecute = 0;
}
//
// copy other bits from target entry
//
@ -547,10 +559,23 @@ EptSplitLargePage(PVMM_EPT_PAGE_TABLE EptPageTable,
//
// Allocate a new pointer which will replace the 2MB entry with a pointer to 512 4096 byte entries
//
NewPointer.AsUInt = 0;
NewPointer.WriteAccess = 1;
NewPointer.ReadAccess = 1;
NewPointer.ExecuteAccess = 1;
NewPointer.AsUInt = 0;
NewPointer.WriteAccess = 1;
NewPointer.ReadAccess = 1;
NewPointer.ExecuteAccess = 1;
//
// Set the UserModeExecute bit based on the global state of MBEC
//
if (g_ModeBasedExecutionControlState)
{
NewPointer.UserModeExecute = 1;
}
else
{
NewPointer.UserModeExecute = 0;
}
NewPointer.PageFrameNumber = (SIZE_T)VirtualAddressToPhysicalAddress(&NewSplit->PML1[0]) / PAGE_SIZE;
//

View file

@ -118,7 +118,6 @@ typedef struct _EPT_STATE
LIST_ENTRY HookedPagesList; // A list of the details about hooked pages
MTRR_RANGE_DESCRIPTOR MemoryRanges[NUM_MTRR_ENTRIES]; // Physical memory ranges described by the BIOS in the MTRRs. Used to build the EPT identity mapping.
UINT32 NumberOfEnabledMemoryRanges; // Number of memory ranges specified in MemoryRanges
PVMM_EPT_PAGE_TABLE EptPageTable; // Page table entries for EPT operation
UINT8 DefaultMemoryType;
} EPT_STATE, *PEPT_STATE;

View file

@ -148,7 +148,7 @@ UdHandleInstantBreak(PROCESSOR_DEBUGGING_STATE * DbgState,
// Since the adding it to the watching list will take effect from the next
// CR3 vm-exit, we should change the state of the core to prevent further execution
//
// ConfigureExecTrapApplyMbecConfiguratinFromKernelSide(DbgState->CoreId);
ConfigureExecTrapApplyMbecConfiguratinFromKernelSide(DbgState->CoreId);
//
// Handling state through the user-mode debugger