76 if (NULL == DataAddress)
81 if (NULL != DataAddress->Entries)
86 if (NULL != DataAddress->Tables)
161 QWORD newValue, oldValue, index, physAddr, gla;
162 BOOLEAN oldP, newP, oldPSE, newPSE;
178 newValue = oldValue = 0;
193 if ((pTable->
Level == 5) && (index >= 256))
196 goto cleanup_and_exit;
202 if ((pTable->
Level == 4) && (index >= 256))
205 goto cleanup_and_exit;
210 if (pTable->
Level == 3)
212 index = (Address & 0x1f) >> 3;
217 goto cleanup_and_exit;
228 if ((pTable->
Level == 2) && (index >= 512))
231 goto cleanup_and_exit;
239 pEntry = &pTable->
Entries[index];
247 goto cleanup_and_exit;
255 goto cleanup_and_exit;
263 ERROR(
"[ERROR] IntHookPtwProcessWrite failed at PTE %llx, CR3 %llx (current), CR3 %llx (hooked): 0x%08x\n",
264 Address, cr3, pTable->
Root->
Cr3, status);
266 ERROR(
"[ERROR] Dumping the entire VASMON tables for VA space %llx...\n", pTable->
Root->
Cr3);
270 ERROR(
"[ERROR] Dumping the entire VASMON tables for VA space %llx DONE!\n", pTable->
Root->
Cr3);
273 goto cleanup_and_exit;
278 goto cleanup_and_exit;
285 oldP = (0 != (oldValue &
PD_P));
286 newP = (0 != (newValue &
PD_P));
287 oldPSE = (oldP && (0 != (oldValue &
PD_PS)));
288 newPSE = (newP && (0 != (newValue &
PD_PS)));
290 if (newP && (0 != (newValue &
PT_US)) && (pTable->
LinearAddress >= 0xFFFF800000000000))
292 LOG(
"[VASMON] Kernel page 0x%016llx is turning into user page from RIP 0x%016llx: 0x%016llx - 0x%016llx, " 296 if (newP && (0 == (newValue & PT_US)) && (pTable->
LinearAddress < 0xFFFF800000000000))
298 LOG(
"[VASMON] User page 0x%016llx is turning into kernel page from RIP 0x%016llx: 0x%016llx - 0x%016llx, " 302 if (pTable->
Level > 1)
305 if (oldP && !oldPSE && (!newP || newPSE))
308 if (NULL != pTable->
Tables[index])
313 ERROR(
"[ERROR] IntVasUnHookTable failed: 0x%08x\n", status);
317 pTable->
Tables[index] = NULL;
319 else if (newP && !newPSE && (!oldP || oldPSE))
323 if (NULL != pTable->
Tables[index])
328 ERROR(
"[ERROR] IntVasUnHookTable failed: 0x%08x\n", status);
331 pTable->
Tables[index] = NULL;
342 ERROR(
"[ERROR] IntVasHookTables failed in root %llx: 0x%08x\n", pTable->
Root->
Cr3, status);
345 else if (oldP && newP && !oldPSE && !newPSE &&
349 if (NULL != pTable->
Tables[index])
354 ERROR(
"[ERROR] IntVasUnHookTable failed: 0x%08x\n", status);
358 pTable->
Tables[index] = NULL;
368 ERROR(
"[ERROR] IntVasHookTables failed in root %llx: 0x%08x\n", pTable->
Root->
Cr3, status);
377 ((1 == pTable->
Level) || oldPSE || newPSE))
390 if (NULL != callback)
392 status = callback(context, gla, oldValue, newValue, pageSize);
395 ERROR(
"[ERROR] callback failed: 0x%08x\n", status);
436 QWORD localLinearAddress;
441 if (0 == CurrentPage)
465 pTable->
Level = Level;
473 (
PAGING_PAE_MODE == PagingMode ? (3 == Level ? 0x20 : 0x1000) : (0x1000)),
483 ERROR(
"[ERROR] IntHookGpaSetHook failed: 0x%08x\n", status);
532 if (NULL == pTable->
Tables)
556 ERROR(
"[ERROR] IntPhysMemMap failed: 0x%08x\n", status);
557 goto cleanup_and_exit;
560 for (i = 0; i < (
DWORD)((5 == Level) ? 256 : 512); i++)
568 if (NULL != pTable->
Tables)
579 else if ((2 == Level) && (0 != (pPage[i] &
PD_PS)))
583 else if ((3 == Level) && (0 != (pPage[i] &
PDP_PS)))
597 ERROR(
"[ERROR] IntVasHookTables failed in root %llx: 0x%08x\n", Root->Cr3, status);
599 goto cleanup_and_exit;
615 ERROR(
"[ERROR] IntPhysMemMap failed: 0x%08x\n", status);
616 goto cleanup_and_exit;
619 for (i = 0; i < (
DWORD)((4 == Level) ? 256 : 512); i++)
627 if (NULL != pTable->
Tables)
638 else if ((2 == Level) && (0 != (pPage[i] &
PD_PS)))
642 else if ((3 == Level) && (0 != (pPage[i] &
PDP_PS)))
656 ERROR(
"[ERROR] IntVasHookTables failed in root %llx: 0x%08x\n", Root->Cr3, status);
658 goto cleanup_and_exit;
681 ERROR(
"[ERROR] IntPhysMemMap failed: 0x%08x\n", status);
682 goto cleanup_and_exit;
693 if (NULL != pTable->
Tables)
704 else if ((2 == Level) && (0 != (pPage[i] &
PD_PS)))
718 ERROR(
"[ERROR] IntVasHookTables failed in root %llx: 0x%08x\n", Root->Cr3, status);
720 goto cleanup_and_exit;
736 ERROR(
"[ERROR] IntPhysMemMap failed: 0x%08x\n", status);
737 goto cleanup_and_exit;
740 for (i = 0; i < (
DWORD)(2 == Level ? 512 : 1024); i++)
748 if (NULL != pTable->
Tables)
759 else if ((2 == Level) && (0 != (pPage[i] &
PD_PS)))
773 ERROR(
"[ERROR] IntVasHookTables failed in root %llx: 0x%08x\n", Root->Cr3, status);
775 goto cleanup_and_exit;
816 if (NULL != Table->WriteHook)
821 ERROR(
"[ERROR] IntHookGpaRemoveHook failed: 0x%08x\n", status);
826 if (NULL != Table->Entries)
828 for (
DWORD i = 0; i < Table->EntriesCount; i++)
831 if ((NULL != Table->Tables) && (NULL != Table->Tables[i]))
836 ERROR(
"[ERROR] IntVasUnHookTable failed: 0x%08x\n", status);
846 callback = Table->Root->Callback;
848 context = Table->Root->Context;
852 gla =
VAS_COMPUTE_GLA(Table->LinearAddress, i, Table->Level, Table->PagingMode);
856 status = callback(context, gla, Table->Entries[i].WriteState.CurEntry, 0, pageSize);
859 ERROR(
"[ERROR] VAS callback failed: 0x%08x\n", status);
868 ERROR(
"[ERROR] IntVasCleanupCallback failed: 0x%08x\n", status);
911 if (NULL == Callback)
922 if (NULL == pVasRoot)
946 WARNING(
"[WARNING] The paging mode of the system is 32 bit without PAE! Protection is limited (no NX)!\n");
956 ERROR(
"[ERROR] Failed initiating VA space monitoring for CR3 0x%016llx: 0x%08x\n", Cr3, status);
959 if (NULL != pVasRoot->
Table)
1007 if (pRoot->
Cr3 == Cr3)
1023 ERROR(
"[ERROR] IntVasUnHookTables failed: 0x%08x\n", status);
1049 CHAR *spaces[5] = {
"",
" ",
" ",
" ",
" ", };
1051 LOG(
" %s level %d: CUR %llx, INT %llx, mask %x, GPA %llx, GLA %llx\n",
1052 spaces[Table->Level], Table->Level,
1053 Parent ? Parent->WriteState.CurEntry : 0,
1054 Parent ? Parent->WriteState.IntEntry : 0,
1055 Parent ? Parent->WriteState.WrittenMask : 0,
1057 Table->LinearAddress);
1059 if (NULL == Table->Tables)
1064 for (i = 0; i < Table->EntriesCount; i++)
1066 if (NULL != Table->Tables[i])
1101 if (pRoot->
Cr3 == Cr3)
1117 ERROR(
"[ERROR] IntVasUnHookTables failed: 0x%08x\n", status);
1160 memzero(&gVasState,
sizeof(gVasState));
#define VAS_COMPUTE_GLA_PAE(Base, Index, Level)
#define INT_STATUS_PAGE_NOT_PRESENT
Indicates that a virtual address is not present.
#define CONTAINING_RECORD(List, Type, Member)
static QWORD IntVasGetPageSize(PVAS_TABLE Table)
Computes the size of a page, given a VAS table.
INTSTATUS IntVasDump(QWORD Cr3)
Dump the monitored tables for the indicated Cr3.
IG_ARCH_REGS Regs
The current state of the guest registers.
DWORD Index
The VCPU number.
INTSTATUS IntHookGpaRemoveHook(HOOK_GPA **Hook, DWORD Flags)
Remove a GPA hook.
struct _VAS_STATE * PVAS_STATE
INTSTATUS IntVasUnInit(void)
Uninit the VAS monitor state.
#define CLEAN_PHYS_ADDRESS64(x)
#define INT_STATUS_SUCCESS
struct _LIST_ENTRY * Flink
#define VAS_COMPUTE_GLA_32(Base, Index, Level)
QWORD LinearAddress
The first linear address translated by this table.
#define INT_SUCCESS(Status)
INTSTATUS IntResumeVcpus(void)
Resumes the VCPUs previously paused with IntPauseVcpus.
BYTE PagingMode
Paging mode.
Measures page table writes done by the VAS monitor.
BYTE Level
The level of the current page table.
#define INT_STATUS_NOT_NEEDED_HINT
static INTSTATUS IntVasHookTables(QWORD LinearAddress, QWORD CurrentPage, BYTE PagingMode, BYTE Level, PVAS_ROOT Root, PVAS_TABLE *Table)
Recursively hook all the page-tables starting with the indicated page-table.
#define HpAllocWithTag(Len, Tag)
int INTSTATUS
The status data type.
LIST_ENTRY Link
List entry link.
static VAS_STATE gVasState
static INTSTATUS IntVasDumpTables(PVAS_TABLE Table, PVAS_TABLE_ENTRY Parent)
Dump the VAS tables.
#define INT_STATUS_NOT_FOUND
#define VAS_COMPUTE_GLA_64(Base, Index, Level)
static INTSTATUS IntVasDeleteTable(PVAS_TABLE DataAddress, QWORD DataInfo)
Delete the indicated VAS table.
#define VAS_COMPUTE_GLA(Base, Index, Level, Pg)
INTSTATUS IntPauseVcpus(void)
Pauses all the guest VCPUs.
INTRO_GUEST_TYPE OSType
The type of the guest.
INTSTATUS IntHookGpaSetHook(QWORD Gpa, DWORD Length, BYTE Type, PFUNC_EptViolationCallback Callback, void *Context, void *ParentHook, DWORD Flags, HOOK_GPA **Hook)
Places an EPT hook on the indicated memory range.
INTSTATUS IntVasStartMonitorVaSpace(QWORD Cr3, PFUNC_VaSpaceModificationCallback Callback, void *Context, QWORD MonitoredBits, void **Root)
Start monitoring the indicated virtual address space.
struct _VAS_ROOT * Root
The root handle.
HOOK_PTEWS WriteState
Write state of each page-table entry.
#define HOOK_FLG_PAGING_STRUCTURE
If flag is set, the hook is set on paging structures.
struct _VAS_TABLE * PVAS_TABLE
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
void * Context
Optional context, will be passed to the callback.
LIST_HEAD MonitoredSpaces
List of monitored virtual address spaces.
#define INT_STATUS_INVALID_PARAMETER_4
#define HpFreeAndNullWithTag(Add, Tag)
#define INT_STATUS_INVALID_PARAMETER_5
#define INT_STATUS_INVALID_INTERNAL_STATE
static INTSTATUS IntVasUnHookTables(PVAS_TABLE Table)
Every table starting with this one will be deleted.
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
void * WriteHook
The write hook handle.
PVAS_TABLE Table
This entry will contain the data associated to the PML4/PDP/PD - the first level. ...
static void InitializeListHead(LIST_ENTRY *ListHead)
struct _VAS_TABLE ** Tables
Pointer to children tables, for each valid entry. NULL for leafs.
PVAS_TABLE_ENTRY Entries
Children entries.
#define UNREFERENCED_PARAMETER(P)
BOOLEAN Initialized
Set once the state is initialized.
QWORD MonitoredBits
Monitored bits inside page-table entries.
#define INT_STATUS_INVALID_PARAMETER_6
PFUNC_VaSpaceModificationCallback Callback
enum _INTRO_ACTION INTRO_ACTION
Event actions.
QWORD CurEntry
Current page-table entry value.
#define IntDbgEnterDebugger()
WORD EntriesCount
The number of entries. It can vary from 4 to 512 to 1024, depending on mode.
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
GUEST_STATE gGuest
The current guest state.
INTSTATUS(* PFUNC_VaSpaceModificationCallback)(void *Context, QWORD VirtualAddress, QWORD OldEntry, QWORD NewEntry, QWORD PageSize)
Translation modification callback.
INTSTATUS IntVasPageTableWriteCallback(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Handle writes inside the monitored page-tables.
#define INT_STATUS_PARTIAL_WRITE
#define INT_STATUS_NO_MAPPING_STRUCTURES
Indicates that not all mapping structures of a virtual address are present.
PAGING_MODE Mode
The paging mode used by the guest.
INTSTATUS IntCr3Read(DWORD CpuNumber, QWORD *Cr3Value)
Reads the value of the guest CR3.
__must_check INTSTATUS IntPhysMemMap(QWORD PhysAddress, DWORD Length, DWORD Flags, void **HostPtr)
Maps a guest physical address inside Introcore VA space.
#define INT_STATUS_NOT_INITIALIZED_HINT
#define INT_STATUS_INVALID_PARAMETER_1
#define INT_STATUS_NOT_SUPPORTED
VCPU_STATE * gVcpu
The state of the current VCPU.
struct _VAS_STATE VAS_STATE
INTSTATUS IntVasStopMonitorVaSpace(QWORD Cr3, PVAS_ROOT Root)
Stops monitoring the indicated virtual address space.
INTSTATUS IntVasInit(void)
Initialize the VAS monitor state.
QWORD Cr3
Monitored virtual address space.
unsigned long long * PQWORD
INTSTATUS IntPhysMemUnmap(void **HostPtr)
Unmaps an address previously mapped with IntPhysMemMap.
#define INT_STATUS_INVALID_PARAMETER_2
INTSTATUS IntHookPtwProcessWrite(PHOOK_PTEWS WriteState, QWORD Address, BYTE EntrySize, QWORD *OldValue, QWORD *NewValue)
Processes a page-table write, returning the old and the new page-table entry value.
#define INT_STATUS_INSUFFICIENT_RESOURCES
#define INT_STATUS_INVALID_PARAMETER_3