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

This file shows the functions to map memory to reserved system ranges. More...

#include "pch.h"

Functions

_Use_decl_annotations_ UINT64 MemoryMapperGetIndex (PAGING_LEVEL Level, UINT64 Va)
 Get Index of VA on PMLx.
 
_Use_decl_annotations_ UINT32 MemoryMapperGetOffset (PAGING_LEVEL Level, UINT64 Va)
 Get page offset.
 
_Use_decl_annotations_ PVOID MemoryMapperGetPteVa (PVOID Va, PAGING_LEVEL Level)
 This function gets virtual address and returns its PTE of the virtual address.
 
_Use_decl_annotations_ PVOID MemoryMapperGetPteVaByCr3 (PVOID Va, PAGING_LEVEL Level, CR3_TYPE TargetCr3)
 This function gets virtual address and returns its PTE of the virtual address based on the specific cr3.
 
_Use_decl_annotations_ PVOID MemoryMapperGetPteVaOnTargetProcess (PVOID Va, PAGING_LEVEL Level)
 This function gets virtual address and returns its PTE of the virtual address based on the target virtual address.
 
BOOLEAN MemoryMapperCheckPteIsPresentOnTargetProcess (PVOID Va, PAGING_LEVEL Level)
 This function checks whether the virtual address is present in the RAM or not.
 
_Use_decl_annotations_ PVOID MemoryMapperSetExecuteDisableToPteOnTargetProcess (PVOID Va, BOOLEAN Set)
 This function gets virtual address and returns its PTE of the virtual address based on the target virtual address.
 
_Use_decl_annotations_ PVOID MemoryMapperGetPteVaWithoutSwitchingByCr3 (PVOID Va, PAGING_LEVEL Level, CR3_TYPE TargetCr3)
 This function gets virtual address and returns its PTE of the virtual address based on the specific cr3 but without switching to the target address.
 
_Use_decl_annotations_ BOOLEAN MemoryMapperCheckIfPageIsPresentByCr3 (PVOID Va, CR3_TYPE TargetCr3)
 This function checks if the page is mapped or not.
 
_Use_decl_annotations_ BOOLEAN MemoryMapperCheckIfPageIsNxBitSetByCr3 (PVOID Va, CR3_TYPE TargetCr3)
 This function checks if the page has NX bit or not.
 
_Use_decl_annotations_ BOOLEAN MemoryMapperCheckIfPageIsNxBitSetOnTargetProcess (PVOID Va)
 This function checks target process to see if the page has NX bit or not.
 
_Use_decl_annotations_ BOOLEAN MemoryMapperCheckIfPdeIsLargePageOnTargetProcess (PVOID Va)
 This function checks target process to see if the PDE is a large page or not.
 
_Use_decl_annotations_ PVOID MemoryMapperMapReservedPageRange (SIZE_T Size)
 This function reserve memory from system range (without physically allocating them)
 
_Use_decl_annotations_ VOID MemoryMapperUnmapReservedPageRange (PVOID VirtualAddress)
 This function frees the memory that was previously allocated from system range (without physically allocating them)
 
_Use_decl_annotations_ PVOID MemoryMapperGetPte (PVOID VirtualAddress)
 This function gets virtual address and returns its PTE (Pml4e) virtual address.
 
_Use_decl_annotations_ PVOID MemoryMapperGetPteByCr3 (PVOID VirtualAddress, CR3_TYPE TargetCr3)
 This function gets virtual address and returns its PTE (Pml4e) virtual address based on a specific Cr3.
 
_Use_decl_annotations_ PVOID MemoryMapperMapPageAndGetPte (PUINT64 PteAddress)
 This function MAPs one resreved page (4096) and returns its virtual adrresss and also PTE virtual address in PteAddress.
 
VOID MemoryMapperInitialize ()
 Initialize the Memory Mapper.
 
VOID MemoryMapperUninitialize ()
 uninitialize the Memory Mapper
 
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeByPte (PHYSICAL_ADDRESS PaAddressToRead, PVOID BufferToSaveMemory, SIZE_T SizeToRead, UINT64 PteVaAddress, UINT64 MappingVa, BOOLEAN InvalidateVpids)
 Read memory safely by mapping the buffer using PTE.
 
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeByPte (PVOID SourceVA, PHYSICAL_ADDRESS PaAddressToWrite, SIZE_T SizeToWrite, UINT64 PteVaAddress, UINT64 MappingVa, BOOLEAN InvalidateVpids)
 Write memory safely by mapping the buffer using PTE.
 
_Use_decl_annotations_ UINT64 MemoryMapperReadMemorySafeByPhysicalAddressWrapperAddressMaker (MEMORY_MAPPER_WRAPPER_FOR_MEMORY_READ TypeOfRead, UINT64 AddressToRead)
 Wrapper to read the memory safely by mapping the buffer by physical address (It's a wrapper)
 
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeByPhysicalAddressWrapper (MEMORY_MAPPER_WRAPPER_FOR_MEMORY_READ TypeOfRead, UINT64 AddressToRead, UINT64 BufferToSaveMemory, SIZE_T SizeToRead)
 Wrapper to read the memory safely by mapping the buffer by physical address (It's a wrapper)
 
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeByPhysicalAddress (UINT64 PaAddressToRead, UINT64 BufferToSaveMemory, SIZE_T SizeToRead)
 Read memory safely by mapping the buffer by physical address (It's a wrapper)
 
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafe (UINT64 VaAddressToRead, PVOID BufferToSaveMemory, SIZE_T SizeToRead)
 Read memory safely by mapping the buffer (It's a wrapper)
 
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeOnTargetProcess (UINT64 VaAddressToRead, PVOID BufferToSaveMemory, SIZE_T SizeToRead)
 Read memory safely by mapping the buffer on the target process memory (It's a wrapper)
 
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeOnTargetProcess (UINT64 Destination, PVOID Source, SIZE_T Size)
 Write memory safely by mapping the buffer on the target process memory (It's a wrapper)
 
_Use_decl_annotations_ UINT64 MemoryMapperWriteMemorySafeWrapperAddressMaker (MEMORY_MAPPER_WRAPPER_FOR_MEMORY_WRITE TypeOfWrite, UINT64 DestinationAddr, PCR3_TYPE TargetProcessCr3, UINT32 TargetProcessId)
 Decides about making the address and converting the address to physical address based on the passed parameters.
 
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeWrapper (MEMORY_MAPPER_WRAPPER_FOR_MEMORY_WRITE TypeOfWrite, UINT64 DestinationAddr, UINT64 Source, SIZE_T SizeToWrite, PCR3_TYPE TargetProcessCr3, UINT32 TargetProcessId)
 Write memory safely by mapping the buffer (It's a wrapper)
 
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafe (UINT64 Destination, PVOID Source, SIZE_T SizeToWrite, CR3_TYPE TargetProcessCr3)
 Write memory by mapping the buffer (It's a wrapper)
 
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemoryUnsafe (UINT64 Destination, PVOID Source, SIZE_T SizeToWrite, UINT32 TargetProcessId)
 Write memory safely by mapping the buffer (It's a wrapper)
 
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeByPhysicalAddress (UINT64 DestinationPa, UINT64 Source, SIZE_T SizeToWrite)
 Write memory safely by mapping the buffer.
 
_Use_decl_annotations_ UINT64 MemoryMapperReserveUsermodeAddressOnTargetProcess (UINT32 ProcessId, BOOLEAN Allocate)
 Reserve user mode address (not allocated) in the target user mode application.
 
_Use_decl_annotations_ BOOLEAN MemoryMapperFreeMemoryOnTargetProcess (UINT32 ProcessId, PVOID BaseAddress)
 Deallocates a previously reserved user mode address in the target user mode application.
 
_Use_decl_annotations_ VOID MemoryMapperMapPhysicalAddressToPte (PHYSICAL_ADDRESS PhysicalAddress, PVOID TargetProcessVirtualAddress, CR3_TYPE TargetProcessKernelCr3)
 Maps a physical address to a PTE.
 
_Use_decl_annotations_ BOOLEAN MemoryMapperSetSupervisorBitWithoutSwitchingByCr3 (PVOID Va, BOOLEAN Set, PAGING_LEVEL Level, CR3_TYPE TargetCr3)
 This function the Supervisor bit of the target PTE based on the specific cr3.
 

Detailed Description

This file shows the functions to map memory to reserved system ranges.

This file shows the header functions to map memory to reserved system ranges.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)

also some of the functions derived from hvpp

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

also some of the functions derived from hvpp

Version
0.1
Date
2020-05-3

Function Documentation

◆ MemoryMapperCheckIfPageIsNxBitSetByCr3()

_Use_decl_annotations_ BOOLEAN MemoryMapperCheckIfPageIsNxBitSetByCr3 ( PVOID Va,
CR3_TYPE TargetCr3 )

This function checks if the page has NX bit or not.

Parameters
VaVirtual Address
TargetCr3kernel cr3 of target process
Returns
PPAGE_ENTRY virtual address of PTE based on cr3
447{
448 PPAGE_ENTRY PageEntry;
449
450 //
451 // Find the page table entry
452 //
453 PageEntry = MemoryMapperGetPteVaByCr3(Va, PagingLevelPageTable, TargetCr3);
454
455 if (PageEntry != NULL && !PageEntry->Fields.ExecuteDisable)
456 {
457 return TRUE;
458 }
459 else
460 {
461 return FALSE;
462 }
463}
#define TRUE
Definition BasicTypes.h:55
#define FALSE
Definition BasicTypes.h:54
@ PagingLevelPageTable
Definition DataTypes.h:25
_Use_decl_annotations_ PVOID MemoryMapperGetPteVaByCr3(PVOID Va, PAGING_LEVEL Level, CR3_TYPE TargetCr3)
This function gets virtual address and returns its PTE of the virtual address based on the specific c...
Definition MemoryMapper.c:88
Page Entries.
Definition MemoryMapper.h:61
struct _PAGE_ENTRY::@2::@4 Fields
UINT64 ExecuteDisable
Definition MemoryMapper.h:93

◆ MemoryMapperCheckIfPageIsNxBitSetOnTargetProcess()

_Use_decl_annotations_ BOOLEAN MemoryMapperCheckIfPageIsNxBitSetOnTargetProcess ( PVOID Va)

This function checks target process to see if the page has NX bit or not.

Parameters
VaVirtual Address
TargetCr3kernel cr3 of target process
Returns
BOOLEAN
476{
477 BOOLEAN Result;
478 CR3_TYPE GuestCr3;
479 PPAGE_ENTRY PageEntry;
480 CR3_TYPE CurrentProcessCr3 = {0};
481
482 //
483 // Move to guest process as we're currently in system cr3
484 //
485
486 //
487 // Find the current process cr3
488 //
490
491 CurrentProcessCr3 = SwitchToProcessMemoryLayoutByCr3(GuestCr3);
492
493 //
494 // Find the page table entry
495 //
497
498 if (PageEntry != NULL && !PageEntry->Fields.ExecuteDisable)
499 {
500 Result = TRUE;
501 }
502 else
503 {
504 Result = FALSE;
505 }
506
507 //
508 // Restore the original process
509 //
510 SwitchToPreviousProcess(CurrentProcessCr3);
511
512 return Result;
513}
UCHAR BOOLEAN
Definition BasicTypes.h:39
CR3_TYPE LayoutGetCurrentProcessCr3()
Get cr3 of the target running process.
Definition Layout.c:55
_Use_decl_annotations_ PVOID MemoryMapperGetPteVa(PVOID Va, PAGING_LEVEL Level)
This function gets virtual address and returns its PTE of the virtual address.
Definition MemoryMapper.c:59
_Use_decl_annotations_ VOID SwitchToPreviousProcess(CR3_TYPE PreviousProcess)
Switch to previous process's cr3.
Definition SwitchLayout.c:125
_Use_decl_annotations_ CR3_TYPE SwitchToProcessMemoryLayoutByCr3(CR3_TYPE TargetCr3)
Switch to another process's cr3.
Definition SwitchLayout.c:99
CR3 Structure.
Definition BasicTypes.h:130
UINT64 Flags
Definition BasicTypes.h:133

◆ MemoryMapperCheckIfPageIsPresentByCr3()

_Use_decl_annotations_ BOOLEAN MemoryMapperCheckIfPageIsPresentByCr3 ( PVOID Va,
CR3_TYPE TargetCr3 )

This function checks if the page is mapped or not.

this function checks for PRESENT Bit of the page table

Parameters
VaVirtual Address
TargetCr3kernel cr3 of target process
Returns
PPAGE_ENTRY virtual address of PTE based on cr3
419{
420 PPAGE_ENTRY PageEntry;
421
422 //
423 // Find the page table entry
424 //
425 PageEntry = MemoryMapperGetPteVaByCr3(Va, PagingLevelPageTable, TargetCr3);
426
427 if (PageEntry != NULL && PageEntry->Fields.Present)
428 {
429 return TRUE;
430 }
431 else
432 {
433 return FALSE;
434 }
435}
UINT64 Present
Definition MemoryMapper.h:79

◆ MemoryMapperCheckIfPdeIsLargePageOnTargetProcess()

_Use_decl_annotations_ BOOLEAN MemoryMapperCheckIfPdeIsLargePageOnTargetProcess ( PVOID Va)

This function checks target process to see if the PDE is a large page or not.

Parameters
VaVirtual Address
TargetCr3kernel cr3 of target process
Returns
BOOLEAN
526{
527 BOOLEAN Result;
528 CR3_TYPE GuestCr3;
529 PPAGE_ENTRY PageEntry;
530 CR3_TYPE CurrentProcessCr3 = {0};
531
532 //
533 // Move to guest process as we're currently in system cr3
534 //
535
536 //
537 // Find the current process cr3
538 //
540
541 CurrentProcessCr3 = SwitchToProcessMemoryLayoutByCr3(GuestCr3);
542
543 //
544 // Find the page table entry (PDE)
545 //
547
548 if (PageEntry != NULL && PageEntry->Fields.LargePage)
549 {
550 Result = TRUE;
551 }
552 else
553 {
554 Result = FALSE;
555 }
556
557 //
558 // Restore the original process
559 //
560 SwitchToPreviousProcess(CurrentProcessCr3);
561
562 return Result;
563}
@ PagingLevelPageDirectory
Definition DataTypes.h:26
UINT64 LargePage
Definition MemoryMapper.h:86

◆ MemoryMapperCheckPteIsPresentOnTargetProcess()

BOOLEAN MemoryMapperCheckPteIsPresentOnTargetProcess ( PVOID Va,
PAGING_LEVEL Level )

This function checks whether the virtual address is present in the RAM or not.

Parameters
VaVirtual Address
LevelPMLx
Returns
BOOLEAN Is present or not
175{
176 PPAGE_ENTRY PageEntry = NULL;
177 CR3_TYPE GuestCr3;
178 CR3_TYPE CurrentProcessCr3 = {0};
179 BOOLEAN Result = FALSE;
180
181 //
182 // Move to guest process as we're currently in system cr3
183 //
184
185 //
186 // Find the current process cr3
187 //
189
190 //
191 // Switch to new process's memory layout
192 // It is because, we're not trying to change the cr3 multiple times
193 // so instead of using PhysicalAddressToVirtualAddressByCr3 we use
194 // PhysicalAddressToVirtualAddress, but keep in mind that cr3 should
195 // be a kernel cr3 (not KPTI user cr3) as the functions to translate
196 // physical address to virtual address is not mapped on the user cr3
197 //
198 CurrentProcessCr3 = SwitchToProcessMemoryLayoutByCr3(GuestCr3);
199
200 //
201 // Call the wrapper
202 //
203 PageEntry = MemoryMapperGetPteVaWithoutSwitchingByCr3(Va, Level, GuestCr3);
204
205 if (PageEntry == NULL)
206 {
207 Result = FALSE;
208 }
209 else
210 {
211 //
212 // Check if page is present or not
213 //
214 if (PageEntry->Fields.Present == TRUE)
215 {
216 //
217 // It's present
218 //
219 Result = TRUE;
220 }
221 else
222 {
223 //
224 // It's not present
225 //
226 Result = FALSE;
227 }
228 }
229
230 //
231 // Restore the original process
232 //
233 SwitchToPreviousProcess(CurrentProcessCr3);
234
235 return Result;
236}
_Use_decl_annotations_ PVOID MemoryMapperGetPteVaWithoutSwitchingByCr3(PVOID Va, PAGING_LEVEL Level, CR3_TYPE TargetCr3)
This function gets virtual address and returns its PTE of the virtual address based on the specific c...
Definition MemoryMapper.c:314
NULL()
Definition test-case-generator.py:530

◆ MemoryMapperFreeMemoryOnTargetProcess()

_Use_decl_annotations_ BOOLEAN MemoryMapperFreeMemoryOnTargetProcess ( UINT32 ProcessId,
PVOID BaseAddress )

Deallocates a previously reserved user mode address in the target user mode application.

this function should be called from vmx non-root mode

Parameters
ProcessIdTarget Process Id
BaseAddressPreviously allocated base address
Returns
BOOLEAN whether the operation was successful or not
1539{
1540 NTSTATUS Status;
1541 SIZE_T AllocSize = PAGE_SIZE;
1542 PEPROCESS SourceProcess;
1543 KAPC_STATE State = {0};
1544
1545 if (PsGetCurrentProcessId() != (HANDLE)ProcessId)
1546 {
1547 //
1548 // User needs another process memory
1549 //
1550
1551 if (PsLookupProcessByProcessId((HANDLE)ProcessId, &SourceProcess) != STATUS_SUCCESS)
1552 {
1553 //
1554 // if the process not found
1555 //
1556 return FALSE;
1557 }
1558 __try
1559 {
1560 KeStackAttachProcess(SourceProcess, &State);
1561
1562 //
1563 // Free memory in target process
1564 //
1565 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
1566 &BaseAddress,
1567 &AllocSize,
1568 MEM_RELEASE);
1569
1570 KeUnstackDetachProcess(&State);
1571
1572 ObDereferenceObject(SourceProcess);
1573 }
1574 __except (EXCEPTION_EXECUTE_HANDLER)
1575 {
1576 KeUnstackDetachProcess(&State);
1577
1578 ObDereferenceObject(SourceProcess);
1579 return FALSE;
1580 }
1581 }
1582 else
1583 {
1584 //
1585 // Deallocate memory in target process
1586 //
1587 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
1588 &BaseAddress,
1589 &AllocSize,
1590 MEM_RELEASE);
1591 }
1592
1593 if (!NT_SUCCESS(Status))
1594 {
1595 return FALSE;
1596 }
1597
1598 //
1599 // Operation was successful
1600 //
1601 return TRUE;
1602}
#define PAGE_SIZE
Size of each page (4096 bytes)
Definition common.h:69

◆ MemoryMapperGetIndex()

_Use_decl_annotations_ UINT64 MemoryMapperGetIndex ( PAGING_LEVEL Level,
UINT64 Va )

Get Index of VA on PMLx.

Parameters
LevelPMLx
VaVirtual Address
Returns
UINT64
26{
27 UINT64 Result = Va;
28 Result >>= 12 + Level * 9;
29
30 return Result;
31}
unsigned __int64 UINT64
Definition BasicTypes.h:21

◆ MemoryMapperGetOffset()

_Use_decl_annotations_ UINT32 MemoryMapperGetOffset ( PAGING_LEVEL Level,
UINT64 Va )

Get page offset.

Parameters
LevelPMLx
VaVirtual Address
Returns
UINT32
43{
44 UINT32 Result = (UINT32)MemoryMapperGetIndex(Level, Va);
45 Result &= (1 << 9) - 1; // 0x1ff
46
47 return Result;
48}
unsigned int UINT32
Definition BasicTypes.h:48
_Use_decl_annotations_ UINT64 MemoryMapperGetIndex(PAGING_LEVEL Level, UINT64 Va)
Get Index of VA on PMLx.
Definition MemoryMapper.c:25

◆ MemoryMapperGetPte()

_Use_decl_annotations_ PVOID MemoryMapperGetPte ( PVOID VirtualAddress)

This function gets virtual address and returns its PTE (Pml4e) virtual address.

Parameters
VirtualAddressVirtual Address
Returns
virtual address of PTE (Pml4e)
605{
606 return MemoryMapperGetPteVa(VirtualAddress, PagingLevelPageTable);
607}

◆ MemoryMapperGetPteByCr3()

_Use_decl_annotations_ PVOID MemoryMapperGetPteByCr3 ( PVOID VirtualAddress,
CR3_TYPE TargetCr3 )

This function gets virtual address and returns its PTE (Pml4e) virtual address based on a specific Cr3.

Parameters
VirtualAddressVirtual Address
TargetCr3Target process cr3
Returns
virtual address of PTE (Pml4e)
620{
621 return MemoryMapperGetPteVaByCr3(VirtualAddress, PagingLevelPageTable, TargetCr3);
622}

◆ MemoryMapperGetPteVa()

_Use_decl_annotations_ PVOID MemoryMapperGetPteVa ( PVOID Va,
PAGING_LEVEL Level )

This function gets virtual address and returns its PTE of the virtual address.

Parameters
VaVirtual Address
LevelPMLx
Returns
PVOID virtual address of PTE
60{
61 CR3_TYPE Cr3;
62
63 //
64 // Read the current cr3
65 //
66 Cr3.Flags = __readcr3();
67
68 //
69 // Call the wrapper
70 //
71 return MemoryMapperGetPteVaWithoutSwitchingByCr3(Va, Level, Cr3);
72}

◆ MemoryMapperGetPteVaByCr3()

_Use_decl_annotations_ PVOID MemoryMapperGetPteVaByCr3 ( PVOID Va,
PAGING_LEVEL Level,
CR3_TYPE TargetCr3 )

This function gets virtual address and returns its PTE of the virtual address based on the specific cr3.

the TargetCr3 should be kernel cr3 as we will use it to translate kernel addresses so the kernel functions to translate addresses should be mapped; thus, don't pass a KPTI meltdown user cr3 to this function

Parameters
VaVirtual Address
LevelPMLx
TargetCr3kernel cr3 of target process
Returns
PVOID virtual address of PTE based on cr3
89{
90 PPAGE_ENTRY PageEntry = NULL;
91 CR3_TYPE CurrentProcessCr3 = {0};
92
93 //
94 // Switch to new process's memory layout
95 // It is because, we're not trying to change the cr3 multiple times
96 // so instead of using PhysicalAddressToVirtualAddressByCr3 we use
97 // PhysicalAddressToVirtualAddress, but keep in mind that cr3 should
98 // be a kernel cr3 (not KPTI user cr3) as the functions to translate
99 // physical address to virtual address is not mapped on the user cr3
100 //
101 CurrentProcessCr3 = SwitchToProcessMemoryLayoutByCr3(TargetCr3);
102
103 //
104 // Call the wrapper
105 //
106 PageEntry = MemoryMapperGetPteVaWithoutSwitchingByCr3(Va, Level, TargetCr3);
107
108 //
109 // Restore the original process
110 //
111 SwitchToPreviousProcess(CurrentProcessCr3);
112
113 return PageEntry;
114}

◆ MemoryMapperGetPteVaOnTargetProcess()

_Use_decl_annotations_ PVOID MemoryMapperGetPteVaOnTargetProcess ( PVOID Va,
PAGING_LEVEL Level )

This function gets virtual address and returns its PTE of the virtual address based on the target virtual address.

Parameters
VaVirtual Address
LevelPMLx
Returns
PVOID virtual address of PTE based on cr3
128{
129 PPAGE_ENTRY PageEntry = NULL;
130 CR3_TYPE GuestCr3;
131 CR3_TYPE CurrentProcessCr3 = {0};
132
133 //
134 // Move to guest process as we're currently in system cr3
135 //
136
137 //
138 // Find the current process cr3
139 //
141
142 //
143 // Switch to new process's memory layout
144 // It is because, we're not trying to change the cr3 multiple times
145 // so instead of using PhysicalAddressToVirtualAddressByCr3 we use
146 // PhysicalAddressToVirtualAddress, but keep in mind that cr3 should
147 // be a kernel cr3 (not KPTI user cr3) as the functions to translate
148 // physical address to virtual address is not mapped on the user cr3
149 //
150 CurrentProcessCr3 = SwitchToProcessMemoryLayoutByCr3(GuestCr3);
151
152 //
153 // Call the wrapper
154 //
155 PageEntry = MemoryMapperGetPteVaWithoutSwitchingByCr3(Va, Level, GuestCr3);
156
157 //
158 // Restore the original process
159 //
160 SwitchToPreviousProcess(CurrentProcessCr3);
161
162 return PageEntry;
163}

◆ MemoryMapperGetPteVaWithoutSwitchingByCr3()

_Use_decl_annotations_ PVOID MemoryMapperGetPteVaWithoutSwitchingByCr3 ( PVOID Va,
PAGING_LEVEL Level,
CR3_TYPE TargetCr3 )

This function gets virtual address and returns its PTE of the virtual address based on the specific cr3 but without switching to the target address.

the TargetCr3 should be kernel cr3 as we will use it to translate kernel addresses so the kernel functions to translate addresses should be mapped; thus, don't pass a KPTI meltdown user cr3 to this function

Parameters
VaVirtual Address
LevelPMLx
TargetCr3kernel cr3 of target process
Returns
PVOID virtual address of PTE based on cr3
315{
316 CR3_TYPE Cr3;
317 UINT64 TempCr3;
318 PUINT64 Cr3Va;
319 PUINT64 PdptVa;
320 PUINT64 PdVa;
321 PUINT64 PtVa;
322 UINT32 Offset;
323
324 Cr3.Flags = TargetCr3.Flags;
325
326 //
327 // Cr3 should be shifted 12 to the left because it's PFN
328 //
329 TempCr3 = Cr3.Fields.PageFrameNumber << 12;
330
331 //
332 // we need VA of Cr3, not PA
333 //
334 Cr3Va = (UINT64 *)PhysicalAddressToVirtualAddress(TempCr3);
335
336 //
337 // Check for invalid address
338 //
339 if (Cr3Va == NULL)
340 {
341 return NULL;
342 }
343
345
346 PPAGE_ENTRY Pml4e = (PAGE_ENTRY *)&Cr3Va[Offset];
347
348 if (!Pml4e->Fields.Present || Level == PagingLevelPageMapLevel4)
349 {
350 return Pml4e;
351 }
352
354
355 //
356 // Check for invalid address
357 //
358 if (PdptVa == NULL)
359 {
360 return NULL;
361 }
362
364
365 PPAGE_ENTRY Pdpte = (PAGE_ENTRY *)&PdptVa[Offset];
366
367 if (!Pdpte->Fields.Present || Pdpte->Fields.LargePage || Level == PagingLevelPageDirectoryPointerTable)
368 {
369 return Pdpte;
370 }
371
373
374 //
375 // Check for invalid address
376 //
377 if (PdVa == NULL)
378 {
379 return NULL;
380 }
381
383
384 PPAGE_ENTRY Pde = (PAGE_ENTRY *)&PdVa[Offset];
385
386 if (!Pde->Fields.Present || Pde->Fields.LargePage || Level == PagingLevelPageDirectory)
387 {
388 return Pde;
389 }
390
392
393 //
394 // Check for invalid address
395 //
396 if (PtVa == NULL)
397 {
398 return NULL;
399 }
400
402
403 PPAGE_ENTRY Pt = (PAGE_ENTRY *)&PtVa[Offset];
404
405 return Pt;
406}
unsigned __int64 * PUINT64
Definition BasicTypes.h:21
_Use_decl_annotations_ UINT64 PhysicalAddressToVirtualAddress(UINT64 PhysicalAddress)
Converts Physical Address to Virtual Address.
Definition Conversion.c:22
@ PagingLevelPageDirectoryPointerTable
Definition DataTypes.h:27
@ PagingLevelPageMapLevel4
Definition DataTypes.h:28
_Use_decl_annotations_ UINT32 MemoryMapperGetOffset(PAGING_LEVEL Level, UINT64 Va)
Get page offset.
Definition MemoryMapper.c:42
struct _CR3_TYPE::@56::@58 Fields
UINT64 PageFrameNumber
Definition BasicTypes.h:138
UINT64 PageFrameNumber
Definition MemoryMapper.h:89

◆ MemoryMapperInitialize()

VOID MemoryMapperInitialize ( )

Initialize the Memory Mapper.

This function should be called in vmx non-root in a IRQL <= APC_LEVEL

Returns
VOID
662{
663 UINT64 TempPte;
664 ULONG ProcessorsCount;
665
666 ProcessorsCount = KeQueryActiveProcessorCount(0);
667
668 //
669 // *** Reserve the address for all cores (read pte and va) ***
670 //
671
672 if (g_MemoryMapper != NULL)
673 {
674 //
675 // It's already initialized
676 //
677 return;
678 }
679
680 //
681 // Allocate the memory buffer structure
682 //
684
685 //
686 // Set the core's id and initialize memory mapper
687 //
688 for (size_t i = 0; i < ProcessorsCount; i++)
689 {
690 //
691 // *** Initialize memory mapper for each core ***
692 //
693
694 //
695 // Initial and reserve for read operations
696 //
699
700 //
701 // Initial and reserve for write operations
702 //
705 }
706}
unsigned long ULONG
Definition BasicTypes.h:37
MEMORY_MAPPER_ADDRESSES * g_MemoryMapper
Save the state of memory mapper.
Definition GlobalVariables.h:44
PVOID PlatformMemAllocateZeroedNonPagedPool(SIZE_T NumberOfBytes)
Allocate a non-paged buffer (zeroed)
Definition Mem.c:69
_Use_decl_annotations_ PVOID MemoryMapperMapPageAndGetPte(PUINT64 PteAddress)
This function MAPs one resreved page (4096) and returns its virtual adrresss and also PTE virtual add...
Definition MemoryMapper.c:633
Memory mapper PTE and reserved virtual address.
Definition MemoryMapper.h:103
UINT64 PteVirtualAddressForRead
Definition MemoryMapper.h:104
UINT64 VirualAddressForRead
Definition MemoryMapper.h:105
UINT64 VirualAddressForWrite
Definition MemoryMapper.h:108
UINT64 PteVirtualAddressForWrite
Definition MemoryMapper.h:107

◆ MemoryMapperMapPageAndGetPte()

_Use_decl_annotations_ PVOID MemoryMapperMapPageAndGetPte ( PUINT64 PteAddress)

This function MAPs one resreved page (4096) and returns its virtual adrresss and also PTE virtual address in PteAddress.

Parameters
PteAddressAddress of Page Table Entry
Returns
virtual address of mapped (not physically) address
634{
635 PVOID Va;
636 UINT64 Pte;
637
638 //
639 // Reserve the page from system va space
640 //
642
643 //
644 // Get the page's Page Table Entry
645 //
646 Pte = (UINT64)MemoryMapperGetPte(Va);
647
648 *PteAddress = Pte;
649
650 return Va;
651}
_Use_decl_annotations_ PVOID MemoryMapperGetPte(PVOID VirtualAddress)
This function gets virtual address and returns its PTE (Pml4e) virtual address.
Definition MemoryMapper.c:604
_Use_decl_annotations_ PVOID MemoryMapperMapReservedPageRange(SIZE_T Size)
This function reserve memory from system range (without physically allocating them)
Definition MemoryMapper.c:573

◆ MemoryMapperMapPhysicalAddressToPte()

_Use_decl_annotations_ VOID MemoryMapperMapPhysicalAddressToPte ( PHYSICAL_ADDRESS PhysicalAddress,
PVOID TargetProcessVirtualAddress,
CR3_TYPE TargetProcessKernelCr3 )

Maps a physical address to a PTE.

Find the PTE from MemoryMapperGetPteVaByCr3

Parameters
PhysicalAddressPhysical Address to be mapped
TargetProcessVirtualAddressVirtual Address of target process
TargetProcessKernelCr3Target process cr3
Returns
VOID
1619{
1620 PPAGE_ENTRY PreviousPteEntry;
1621 PAGE_ENTRY PageEntry;
1622 CR3_TYPE CurrentProcessCr3;
1623
1624 //
1625 // Find the page table entry of the reserved page in the target
1626 // process memory layout
1627 //
1628 PreviousPteEntry = MemoryMapperGetPteVaByCr3(TargetProcessVirtualAddress, PagingLevelPageTable, TargetProcessKernelCr3);
1629
1630 //
1631 // Switch to new process's memory layout
1632 //
1633 CurrentProcessCr3 = SwitchToProcessMemoryLayoutByCr3(TargetProcessKernelCr3);
1634
1635 //
1636 // Read the previous entry in order to modify it
1637 //
1638 PageEntry.Flags = PreviousPteEntry->Flags;
1639
1640 //
1641 // Make sure that the target PTE is readable, writable, executable
1642 // present, global, etc.
1643 //
1644 PageEntry.Fields.Present = 1;
1645
1646 //
1647 // It's not a supervisor page
1648 //
1649 PageEntry.Fields.Supervisor = 1;
1650
1651 //
1652 // Generally we want each page to be writable
1653 //
1654 PageEntry.Fields.Write = 1;
1655
1656 //
1657 // Do not flush this page from the TLB on CR3 switch, by setting the
1658 // global bit in the PTE.
1659 //
1660 PageEntry.Fields.Global = 1;
1661
1662 //
1663 // Set the PFN of this PTE to that of the provided physical address.
1664 //
1665 PageEntry.Fields.PageFrameNumber = PhysicalAddress.QuadPart >> 12;
1666
1667 //
1668 // Apply the page entry in a single instruction
1669 //
1670 PreviousPteEntry->Flags = PageEntry.Flags;
1671
1672 //
1673 // Finally, invalidate the caches for the virtual address
1674 // It's not mandatory to invalidate the address in the VM nested-virtualization
1675 // because it will be automatically invalidated by the top hypervisor, however,
1676 // we should use invlpg in physical computers as it won't invalidate it automatically
1677 //
1678 __invlpg(TargetProcessVirtualAddress);
1679
1680 //
1681 // Restore the original process
1682 //
1683 SwitchToPreviousProcess(CurrentProcessCr3);
1684}
UINT64 Write
Definition MemoryMapper.h:80
UINT64 Global
Definition MemoryMapper.h:87
UINT64 Supervisor
Definition MemoryMapper.h:81
UINT64 Flags
Definition MemoryMapper.h:64

◆ MemoryMapperMapReservedPageRange()

_Use_decl_annotations_ PVOID MemoryMapperMapReservedPageRange ( SIZE_T Size)

This function reserve memory from system range (without physically allocating them)

Parameters
SizeSize of reserving buffers
Returns
PVOID Return the VA of the page
574{
575 //
576 // The MmAllocateMappingAddress routine reserves a range of
577 // system virtual address space of the specified size.
578 //
579 return MmAllocateMappingAddress(Size, POOLTAG);
580}
#define POOLTAG
Pool tag.
Definition Constants.h:417

◆ MemoryMapperReadMemorySafe()

_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafe ( UINT64 VaAddressToRead,
PVOID BufferToSaveMemory,
SIZE_T SizeToRead )

Read memory safely by mapping the buffer (It's a wrapper)

Parameters
VaAddressToReadVirtual Address to read
BufferToSaveMemoryDestination to save
SizeToReadSize
Returns
BOOLEAN if it was successful the returns TRUE and if it was unsuccessful then it returns FALSE
1102{
1104 VaAddressToRead,
1105 (UINT64)BufferToSaveMemory,
1106 SizeToRead);
1107}
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeByPhysicalAddressWrapper(MEMORY_MAPPER_WRAPPER_FOR_MEMORY_READ TypeOfRead, UINT64 AddressToRead, UINT64 BufferToSaveMemory, SIZE_T SizeToRead)
Wrapper to read the memory safely by mapping the buffer by physical address (It's a wrapper)
Definition MemoryMapper.c:971
@ MEMORY_MAPPER_WRAPPER_READ_VIRTUAL_MEMORY
Definition MemoryMapper.h:37

◆ MemoryMapperReadMemorySafeByPhysicalAddress()

_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeByPhysicalAddress ( UINT64 PaAddressToRead,
UINT64 BufferToSaveMemory,
SIZE_T SizeToRead )

Read memory safely by mapping the buffer by physical address (It's a wrapper)

Parameters
PaAddressToReadPhysical Address to read
BufferToSaveMemoryDestination to save
SizeToReadSize
Returns
BOOLEAN if it was successful the returns TRUE and if it was unsuccessful then it returns FALSE
1080{
1081 //
1082 // Call the wrapper
1083 //
1085 PaAddressToRead,
1086 BufferToSaveMemory,
1087 SizeToRead);
1088}
@ MEMORY_MAPPER_WRAPPER_READ_PHYSICAL_MEMORY
Definition MemoryMapper.h:36

◆ MemoryMapperReadMemorySafeByPhysicalAddressWrapper()

_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeByPhysicalAddressWrapper ( MEMORY_MAPPER_WRAPPER_FOR_MEMORY_READ TypeOfRead,
UINT64 AddressToRead,
UINT64 BufferToSaveMemory,
SIZE_T SizeToRead )

Wrapper to read the memory safely by mapping the buffer by physical address (It's a wrapper)

Parameters
TypeOfReadType of read
AddressToReadAddress to read
BufferToSaveMemoryDestination to save
SizeToReadSize
Returns
BOOLEAN if it was successful the returns TRUE and if it was unsuccessful then it returns FALSE
976{
977 ULONG CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
978 UINT64 AddressToCheck;
979 PHYSICAL_ADDRESS PhysicalAddress;
980
981 //
982 // Check to see if PTE and Reserved VA already initialized
983 //
984 if (g_MemoryMapper[CurrentCore].VirualAddressForRead == NULL64_ZERO ||
985 g_MemoryMapper[CurrentCore].PteVirtualAddressForRead == NULL64_ZERO)
986 {
987 //
988 // Not initialized
989 //
990 return FALSE;
991 }
992
993 //
994 // Check whether we should apply multiple accesses or not
995 //
996 AddressToCheck = (CHAR *)AddressToRead + SizeToRead - ((CHAR *)PAGE_ALIGN(AddressToRead));
997
998 if (AddressToCheck > PAGE_SIZE)
999 {
1000 //
1001 // Address should be accessed in more than one page
1002 //
1003 UINT64 ReadSize = AddressToCheck;
1004
1005 while (SizeToRead != 0)
1006 {
1007 ReadSize = (UINT64)PAGE_ALIGN(AddressToRead + PAGE_SIZE) - AddressToRead;
1008
1009 if (ReadSize == PAGE_SIZE && SizeToRead < PAGE_SIZE)
1010 {
1011 ReadSize = SizeToRead;
1012 }
1013
1014 /*
1015 LogInfo("Addr From : %llx to Addr To : %llx | ReadSize : %llx\n",
1016 AddressToRead,
1017 AddressToRead + ReadSize,
1018 ReadSize);
1019 */
1020
1021 //
1022 // One access is enough (page+size won't pass from the PAGE_ALIGN boundary)
1023 //
1024 PhysicalAddress.QuadPart = MemoryMapperReadMemorySafeByPhysicalAddressWrapperAddressMaker(TypeOfRead,
1025 AddressToRead);
1026
1028 PhysicalAddress,
1029 (PVOID)BufferToSaveMemory,
1030 ReadSize,
1031 g_MemoryMapper[CurrentCore].PteVirtualAddressForRead,
1032 g_MemoryMapper[CurrentCore].VirualAddressForRead,
1033 FALSE))
1034 {
1035 return FALSE;
1036 }
1037
1038 //
1039 // Apply the changes to the next addresses (if any)
1040 //
1041 SizeToRead = SizeToRead - ReadSize;
1042 AddressToRead = AddressToRead + ReadSize;
1043 BufferToSaveMemory = BufferToSaveMemory + ReadSize;
1044 }
1045
1046 return TRUE;
1047 }
1048 else
1049 {
1050 //
1051 // One access is enough (page+size won't pass from the PAGE_ALIGN boundary)
1052 //
1053 PhysicalAddress.QuadPart = MemoryMapperReadMemorySafeByPhysicalAddressWrapperAddressMaker(TypeOfRead,
1054 AddressToRead);
1055
1057 PhysicalAddress,
1058 (PVOID)BufferToSaveMemory,
1059 SizeToRead,
1060 g_MemoryMapper[CurrentCore].PteVirtualAddressForRead,
1061 g_MemoryMapper[CurrentCore].VirualAddressForRead,
1062 FALSE);
1063 }
1064}
#define NULL64_ZERO
Definition BasicTypes.h:52
char CHAR
Definition BasicTypes.h:31
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeByPte(PHYSICAL_ADDRESS PaAddressToRead, PVOID BufferToSaveMemory, SIZE_T SizeToRead, UINT64 PteVaAddress, UINT64 MappingVa, BOOLEAN InvalidateVpids)
Read memory safely by mapping the buffer using PTE.
Definition MemoryMapper.c:761
_Use_decl_annotations_ UINT64 MemoryMapperReadMemorySafeByPhysicalAddressWrapperAddressMaker(MEMORY_MAPPER_WRAPPER_FOR_MEMORY_READ TypeOfRead, UINT64 AddressToRead)
Wrapper to read the memory safely by mapping the buffer by physical address (It's a wrapper)
Definition MemoryMapper.c:929
#define PAGE_ALIGN(Va)
Aligning a page.
Definition common.h:75

◆ MemoryMapperReadMemorySafeByPhysicalAddressWrapperAddressMaker()

_Use_decl_annotations_ UINT64 MemoryMapperReadMemorySafeByPhysicalAddressWrapperAddressMaker ( MEMORY_MAPPER_WRAPPER_FOR_MEMORY_READ TypeOfRead,
UINT64 AddressToRead )

Wrapper to read the memory safely by mapping the buffer by physical address (It's a wrapper)

Parameters
TypeOfReadType of read
AddressToReadPhysical Address to read
Returns
UINT64 returns the target physical address and NULL if it fails
932{
933 PHYSICAL_ADDRESS PhysicalAddress = {0};
934
935 switch (TypeOfRead)
936 {
938
939 PhysicalAddress.QuadPart = AddressToRead;
940
941 break;
942
944
945 PhysicalAddress.QuadPart = VirtualAddressToPhysicalAddress((PVOID)AddressToRead);
946
947 break;
948
949 default:
950
951 return NULL64_ZERO;
952 break;
953 }
954
955 return PhysicalAddress.QuadPart;
956}
_Use_decl_annotations_ UINT64 VirtualAddressToPhysicalAddress(_In_ PVOID VirtualAddress)
Converts Virtual Address to Physical Address.
Definition Conversion.c:154

◆ MemoryMapperReadMemorySafeByPte()

_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeByPte ( PHYSICAL_ADDRESS PaAddressToRead,
PVOID BufferToSaveMemory,
SIZE_T SizeToRead,
UINT64 PteVaAddress,
UINT64 MappingVa,
BOOLEAN InvalidateVpids )

Read memory safely by mapping the buffer using PTE.

Parameters
PaAddressToReadPhysical address to read
BufferToSaveMemorybuffer to save the memory
SizeToReadSize
PteVaAddressVirtual Address of PTE
MappingVaMapping virtual address
InvalidateVpidswhether invalidate based on VPIDs or not
Returns
BOOLEAN returns TRUE if it was successful and FALSE if there was error
767{
768 PVOID NewAddress;
769 PAGE_ENTRY PageEntry;
770 PPAGE_ENTRY Pte = (PAGE_ENTRY *)PteVaAddress;
771 PVOID Va = (PVOID)MappingVa;
772
773 //
774 // Copy the previous entry into the new entry
775 //
776 PageEntry.Flags = Pte->Flags;
777
778 PageEntry.Fields.Present = 1;
779
780 //
781 // Generally we want each page to be writable
782 //
783 PageEntry.Fields.Write = 1;
784
785 //
786 // Do not flush this page from the TLB on CR3 switch, by setting the
787 // global bit in the PTE.
788 //
789 PageEntry.Fields.Global = 1;
790
791 //
792 // Set the PFN of this PTE to that of the provided physical address,
793 //
794 PageEntry.Fields.PageFrameNumber = PaAddressToRead.QuadPart >> 12;
795
796 //
797 // Apply the page entry in a single instruction
798 //
799 Pte->Flags = PageEntry.Flags;
800
801 //
802 // Finally, invalidate the caches for the virtual address
803 // It's not mandatory to invalidate the address in the VM nested-virtualization
804 // because it will be automatically invalidated by the top hypervisor, however,
805 // we should use invlpg in physical computers as it won't invalidate it automatically
806 //
807 __invlpg(Va);
808
809 //
810 // Also invalidate it from vpids if we're in vmx root
811 //
812 if (InvalidateVpids)
813 {
814 // __invvpid_addr(VPID_TAG, Va);
815 }
816
817 //
818 // Compute the address
819 //
820 NewAddress = (PVOID)((UINT64)Va + (PAGE_4KB_OFFSET & (PaAddressToRead.QuadPart)));
821
822 //
823 // Move the address into the buffer in a safe manner
824 //
825 memcpy(BufferToSaveMemory, NewAddress, SizeToRead);
826
827 //
828 // Unmap Address
829 //
830 Pte->Flags = NULL64_ZERO;
831
832 return TRUE;
833}
#define PAGE_4KB_OFFSET
Definition MemoryMapper.h:21

◆ MemoryMapperReadMemorySafeOnTargetProcess()

_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafeOnTargetProcess ( UINT64 VaAddressToRead,
PVOID BufferToSaveMemory,
SIZE_T SizeToRead )

Read memory safely by mapping the buffer on the target process memory (It's a wrapper)

Parameters
VaAddressToReadVirtual Address to read
BufferToSaveMemoryDestination to save
SizeToReadSize
Returns
BOOLEAN if it was successful the returns TRUE and if it was unsuccessful then it returns FALSE
1121{
1122 CR3_TYPE GuestCr3;
1123 CR3_TYPE OriginalCr3;
1124 BOOLEAN Result;
1125
1126 //
1127 // Move to guest process as we're currently in system cr3
1128 //
1129
1130 //
1131 // Find the current process cr3
1132 //
1134
1135 //
1136 // Move to new cr3
1137 //
1138 OriginalCr3.Flags = __readcr3();
1139 __writecr3(GuestCr3.Flags);
1140
1141 //
1142 // Read target memory
1143 //
1144 Result = MemoryMapperReadMemorySafe(VaAddressToRead, BufferToSaveMemory, SizeToRead);
1145
1146 //
1147 // Move back to original cr3
1148 //
1149 __writecr3(OriginalCr3.Flags);
1150
1151 return Result;
1152}
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafe(UINT64 VaAddressToRead, PVOID BufferToSaveMemory, SIZE_T SizeToRead)
Read memory safely by mapping the buffer (It's a wrapper)
Definition MemoryMapper.c:1101

◆ MemoryMapperReserveUsermodeAddressOnTargetProcess()

_Use_decl_annotations_ UINT64 MemoryMapperReserveUsermodeAddressOnTargetProcess ( UINT32 ProcessId,
BOOLEAN Allocate )

Reserve user mode address (not allocated) in the target user mode application.

this function should be called from vmx non-root mode

Parameters
ProcessIdTarget Process Id
AllocateWhether allocate or just reserve
Returns
Reserved address in the target user mode application
1458{
1459 NTSTATUS Status;
1460 PVOID AllocPtr = NULL;
1461 SIZE_T AllocSize = PAGE_SIZE;
1462 PEPROCESS SourceProcess;
1463 KAPC_STATE State = {0};
1464
1465 if (PsGetCurrentProcessId() != (HANDLE)ProcessId)
1466 {
1467 //
1468 // User needs another process memory
1469 //
1470
1471 if (PsLookupProcessByProcessId((HANDLE)ProcessId, &SourceProcess) != STATUS_SUCCESS)
1472 {
1473 //
1474 // if the process not found
1475 //
1476 return NULL64_ZERO;
1477 }
1478 __try
1479 {
1480 KeStackAttachProcess(SourceProcess, &State);
1481
1482 //
1483 // Allocate (not allocate, just reserve or reserve and allocate) in memory in target process
1484 //
1485 Status = ZwAllocateVirtualMemory(
1486 NtCurrentProcess(),
1487 &AllocPtr,
1488 (ULONG_PTR)NULL,
1489 &AllocSize,
1490 Allocate ? MEM_COMMIT : MEM_RESERVE,
1491 PAGE_EXECUTE_READWRITE);
1492
1493 KeUnstackDetachProcess(&State);
1494
1495 ObDereferenceObject(SourceProcess);
1496 }
1497 __except (EXCEPTION_EXECUTE_HANDLER)
1498 {
1499 KeUnstackDetachProcess(&State);
1500
1501 ObDereferenceObject(SourceProcess);
1502 return NULL64_ZERO;
1503 }
1504 }
1505 else
1506 {
1507 //
1508 // Allocate in memory in target process
1509 //
1510 Status = ZwAllocateVirtualMemory(
1511 NtCurrentProcess(),
1512 &AllocPtr,
1513 (ULONG_PTR)NULL,
1514 &AllocSize,
1515 Allocate ? MEM_COMMIT : MEM_RESERVE,
1516 PAGE_EXECUTE_READWRITE);
1517 }
1518
1519 if (!NT_SUCCESS(Status))
1520 {
1521 return NULL64_ZERO;
1522 }
1523
1524 return (UINT64)AllocPtr;
1525}

◆ MemoryMapperSetExecuteDisableToPteOnTargetProcess()

_Use_decl_annotations_ PVOID MemoryMapperSetExecuteDisableToPteOnTargetProcess ( PVOID Va,
BOOLEAN Set )

This function gets virtual address and returns its PTE of the virtual address based on the target virtual address.

the TargetCr3 should be kernel cr3 as we will use it to translate kernel addresses so the kernel functions to translate addresses should be mapped; thus, don't pass a KPTI meltdown user cr3 to this function

Parameters
VaVirtual Address
Set
Returns
PVOID virtual address of PTE based on cr3
253{
254 PPAGE_ENTRY PageEntry = NULL;
255 CR3_TYPE GuestCr3;
256 CR3_TYPE CurrentProcessCr3 = {0};
257
258 //
259 // Move to guest process as we're currently in system cr3
260 //
261
262 //
263 // Find the current process cr3
264 //
266
267 //
268 // Switch to new process's memory layout
269 // It is because, we're not trying to change the cr3 multiple times
270 // so instead of using PhysicalAddressToVirtualAddressByCr3 we use
271 // PhysicalAddressToVirtualAddress, but keep in mind that cr3 should
272 // be a kernel cr3 (not KPTI user cr3) as the functions to translate
273 // physical address to virtual address is not mapped on the user cr3
274 //
275 CurrentProcessCr3 = SwitchToProcessMemoryLayoutByCr3(GuestCr3);
276
277 //
278 // Call the wrapper
279 //
281
282 //
283 // Set execute disable bit
284 //
285 PageEntry->Fields.ExecuteDisable = Set;
286
287 //
288 // Invalidate the TLB
289 //
290 __invlpg(Va);
291
292 //
293 // Restore the original process
294 //
295 SwitchToPreviousProcess(CurrentProcessCr3);
296
297 return PageEntry;
298}

◆ MemoryMapperSetSupervisorBitWithoutSwitchingByCr3()

_Use_decl_annotations_ BOOLEAN MemoryMapperSetSupervisorBitWithoutSwitchingByCr3 ( PVOID Va,
BOOLEAN Set,
PAGING_LEVEL Level,
CR3_TYPE TargetCr3 )

This function the Supervisor bit of the target PTE based on the specific cr3.

Parameters
VaVirtual Address
SetSet it to 1 or 0
LevelPMLx
TargetCr3kernel cr3 of target process
Returns
BOOLEAN whether was successful or not
1698{
1699 PPAGE_ENTRY Pml = NULL;
1700
1701 Pml = MemoryMapperGetPteVaWithoutSwitchingByCr3(Va, Level, TargetCr3);
1702
1703 if (!Pml)
1704 {
1705 return FALSE;
1706 }
1707
1708 //
1709 // Change the supervisor bit
1710 //
1711 if (Set)
1712 {
1713 Pml->Fields.Supervisor = 1;
1714 }
1715 else
1716 {
1717 Pml->Fields.Supervisor = 0;
1718 }
1719
1720 return TRUE;
1721}

◆ MemoryMapperUninitialize()

VOID MemoryMapperUninitialize ( )

uninitialize the Memory Mapper

This function should be called in vmx non-root in a IRQL <= APC_LEVEL

Returns
VOID
717{
718 ULONG ProcessorsCount = KeQueryActiveProcessorCount(0);
719
720 for (size_t i = 0; i < ProcessorsCount; i++)
721 {
722 //
723 // Unmap and free the reserved buffer
724 //
725 if (g_MemoryMapper[i].VirualAddressForRead != NULL64_ZERO)
726 {
727 MemoryMapperUnmapReservedPageRange((PVOID)g_MemoryMapper[i].VirualAddressForRead);
728 }
729
730 if (g_MemoryMapper[i].VirualAddressForWrite != NULL64_ZERO)
731 {
732 MemoryMapperUnmapReservedPageRange((PVOID)g_MemoryMapper[i].VirualAddressForWrite);
733 }
734
737
740 }
741
742 //
743 // Set the g_MemoryMapper to null
744 //
746}
_Use_decl_annotations_ VOID MemoryMapperUnmapReservedPageRange(PVOID VirtualAddress)
This function frees the memory that was previously allocated from system range (without physically al...
Definition MemoryMapper.c:591

◆ MemoryMapperUnmapReservedPageRange()

_Use_decl_annotations_ VOID MemoryMapperUnmapReservedPageRange ( PVOID VirtualAddress)

This function frees the memory that was previously allocated from system range (without physically allocating them)

Parameters
VirtualAddressVirtual Address
Returns
VOID
592{
593 MmFreeMappingAddress(VirtualAddress, POOLTAG);
594}

◆ MemoryMapperWriteMemorySafe()

_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafe ( UINT64 Destination,
PVOID Source,
SIZE_T SizeToWrite,
CR3_TYPE TargetProcessCr3 )

Write memory by mapping the buffer (It's a wrapper)

this function CAN be called from vmx-root mode

Parameters
DestinationDestination Virtual Address
SourceSource Virtual Address
SizeToWriteSize
TargetProcessCr3CR3 of target process
Returns
BOOLEAN returns TRUE if it was successful and FALSE if there was error
1388{
1390 Destination,
1391 (UINT64)Source,
1392 SizeToWrite,
1393 &TargetProcessCr3,
1394 NULL_ZERO);
1395}
#define NULL_ZERO
Definition BasicTypes.h:51
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeWrapper(MEMORY_MAPPER_WRAPPER_FOR_MEMORY_WRITE TypeOfWrite, UINT64 DestinationAddr, UINT64 Source, SIZE_T SizeToWrite, PCR3_TYPE TargetProcessCr3, UINT32 TargetProcessId)
Write memory safely by mapping the buffer (It's a wrapper)
Definition MemoryMapper.c:1276
@ MEMORY_MAPPER_WRAPPER_WRITE_VIRTUAL_MEMORY_SAFE
Definition MemoryMapper.h:47

◆ MemoryMapperWriteMemorySafeByPhysicalAddress()

_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeByPhysicalAddress ( UINT64 DestinationPa,
UINT64 Source,
SIZE_T SizeToWrite )

Write memory safely by mapping the buffer.

Parameters
DestinationPaDestination Physical Address
SourceSource Address
SizeToWriteSize
Returns
BOOLEAN returns TRUE if it was successful and FALSE if there was error
1435{
1436 //
1437 // Call the wrapper for safe memory read
1438 //
1440 DestinationPa,
1441 Source,
1442 SizeToWrite,
1443 NULL,
1444 NULL_ZERO);
1445}
@ MEMORY_MAPPER_WRAPPER_WRITE_PHYSICAL_MEMORY
Definition MemoryMapper.h:46

◆ MemoryMapperWriteMemorySafeByPte()

_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeByPte ( PVOID SourceVA,
PHYSICAL_ADDRESS PaAddressToWrite,
SIZE_T SizeToWrite,
UINT64 PteVaAddress,
UINT64 MappingVa,
BOOLEAN InvalidateVpids )

Write memory safely by mapping the buffer using PTE.

Parameters
SourceVASource virtual address
PaAddressToWriteDestination physical address
SizeToWriteSize
PteVaAddressPTE of target virtual address
MappingVaMapping Virtual Address
InvalidateVpidsInvalidate VPIDs or not
Returns
BOOLEAN returns TRUE if it was successful and FALSE if there was error
854{
855 PVOID NewAddress;
856 PAGE_ENTRY PageEntry;
857 PPAGE_ENTRY Pte = (PAGE_ENTRY *)PteVaAddress;
858 PVOID Va = (PVOID)MappingVa;
859
860 //
861 // Copy the previous entry into the new entry
862 //
863 PageEntry.Flags = Pte->Flags;
864
865 PageEntry.Fields.Present = 1;
866
867 //
868 // Generally we want each page to be writable
869 //
870 PageEntry.Fields.Write = 1;
871
872 //
873 // Do not flush this page from the TLB on CR3 switch, by setting the
874 // global bit in the PTE.
875 //
876 PageEntry.Fields.Global = 1;
877
878 //
879 // Set the PFN of this PTE to that of the provided physical address.
880 //
881 PageEntry.Fields.PageFrameNumber = PaAddressToWrite.QuadPart >> 12;
882
883 //
884 // Apply the page entry in a single instruction
885 //
886 Pte->Flags = PageEntry.Flags;
887
888 //
889 // Finally, invalidate the caches for the virtual address.
890 //
891 __invlpg(Va);
892
893 //
894 // Also invalidate it from vpids if we're in vmx root
895 //
896 if (InvalidateVpids)
897 {
898 // __invvpid_addr(VPID_TAG, Va);
899 }
900
901 //
902 // Compute the address
903 //
904 NewAddress = (PVOID)((UINT64)Va + (PAGE_4KB_OFFSET & (PaAddressToWrite.QuadPart)));
905
906 //
907 // Move the address into the buffer in a safe manner
908 //
909 memcpy(NewAddress, SourceVA, SizeToWrite);
910
911 //
912 // Unmap Address
913 //
914 Pte->Flags = NULL64_ZERO;
915
916 return TRUE;
917}

◆ MemoryMapperWriteMemorySafeOnTargetProcess()

_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeOnTargetProcess ( UINT64 Destination,
PVOID Source,
SIZE_T Size )

Write memory safely by mapping the buffer on the target process memory (It's a wrapper)

Parameters
DestinationVirtual Address to write
Sourcevalue to write
SizeSize
Returns
BOOLEAN if it was successful the returns TRUE and if it was unsuccessful then it returns FALSE
1166{
1167 CR3_TYPE GuestCr3;
1168 CR3_TYPE OriginalCr3;
1169 BOOLEAN Result;
1170
1171 //
1172 // *** Move to guest process ***
1173 //
1174
1175 //
1176 // Find the current process cr3
1177 //
1179
1180 //
1181 // Move to new cr3
1182 //
1183 OriginalCr3.Flags = __readcr3();
1184 __writecr3(GuestCr3.Flags);
1185
1186 //
1187 // Write target memory
1188 //
1189 Result = MemoryMapperWriteMemorySafe(Destination, Source, Size, GuestCr3);
1190
1191 //
1192 // Move back to original cr3
1193 //
1194 __writecr3(OriginalCr3.Flags);
1195
1196 return Result;
1197}
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafe(UINT64 Destination, PVOID Source, SIZE_T SizeToWrite, CR3_TYPE TargetProcessCr3)
Write memory by mapping the buffer (It's a wrapper)
Definition MemoryMapper.c:1384

◆ MemoryMapperWriteMemorySafeWrapper()

_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeWrapper ( MEMORY_MAPPER_WRAPPER_FOR_MEMORY_WRITE TypeOfWrite,
UINT64 DestinationAddr,
UINT64 Source,
SIZE_T SizeToWrite,
PCR3_TYPE TargetProcessCr3,
UINT32 TargetProcessId )

Write memory safely by mapping the buffer (It's a wrapper)

Parameters
TypeOfWriteType of memory write
DestinationAddrDestination Address
SourceSource Address
SizeToWriteSize
TargetProcessCr3The process CR3 (might be null)
TargetProcessIdThe process PID (might be null)
Returns
BOOLEAN returns TRUE if it was successful and FALSE if there was error
1282{
1283 ULONG CurrentCore = KeGetCurrentProcessorNumberEx(NULL);
1284 UINT64 AddressToCheck;
1285 PHYSICAL_ADDRESS PhysicalAddress;
1286
1287 //
1288 // Check to see if PTE and Reserved VA already initialized
1289 //
1290 if (g_MemoryMapper[CurrentCore].VirualAddressForWrite == NULL64_ZERO ||
1291 g_MemoryMapper[CurrentCore].PteVirtualAddressForWrite == NULL64_ZERO)
1292 {
1293 //
1294 // Not initialized
1295 //
1296 return FALSE;
1297 }
1298
1299 //
1300 // Check whether it needs multiple accesses to different pages or no
1301 //
1302 AddressToCheck = (CHAR *)DestinationAddr + SizeToWrite - ((CHAR *)PAGE_ALIGN(DestinationAddr));
1303
1304 if (AddressToCheck > PAGE_SIZE)
1305 {
1306 //
1307 // It need multiple accesses to different pages to access the memory
1308 //
1309
1310 UINT64 WriteSize = AddressToCheck;
1311
1312 while (SizeToWrite != 0)
1313 {
1314 WriteSize = (UINT64)PAGE_ALIGN(DestinationAddr + PAGE_SIZE) - DestinationAddr;
1315
1316 if (WriteSize == PAGE_SIZE && SizeToWrite < PAGE_SIZE)
1317 {
1318 WriteSize = SizeToWrite;
1319 }
1320
1321 /*
1322 LogInfo("Addr From : %llx to Addr To : %llx | WriteSize : %llx\n",
1323 DestinationAddr,
1324 DestinationAddr + WriteSize,
1325 WriteSize);
1326 */
1327
1328 PhysicalAddress.QuadPart = MemoryMapperWriteMemorySafeWrapperAddressMaker(TypeOfWrite,
1329 DestinationAddr,
1330 TargetProcessCr3,
1331 TargetProcessId);
1332
1334 (PVOID)Source,
1335 PhysicalAddress,
1336 WriteSize,
1337 g_MemoryMapper[CurrentCore].PteVirtualAddressForWrite,
1338 g_MemoryMapper[CurrentCore].VirualAddressForWrite,
1339 FALSE))
1340 {
1341 return FALSE;
1342 }
1343
1344 SizeToWrite = SizeToWrite - WriteSize;
1345 DestinationAddr = DestinationAddr + WriteSize;
1346 Source = Source + WriteSize;
1347 }
1348
1349 return TRUE;
1350 }
1351 else
1352 {
1353 //
1354 // One access is enough to write
1355 //
1356 PhysicalAddress.QuadPart = MemoryMapperWriteMemorySafeWrapperAddressMaker(TypeOfWrite,
1357 DestinationAddr,
1358 TargetProcessCr3,
1359 TargetProcessId);
1361 (PVOID)Source,
1362 PhysicalAddress,
1363 SizeToWrite,
1364 g_MemoryMapper[CurrentCore].PteVirtualAddressForWrite,
1365 g_MemoryMapper[CurrentCore].VirualAddressForWrite,
1366 FALSE);
1367 }
1368}
_Use_decl_annotations_ UINT64 MemoryMapperWriteMemorySafeWrapperAddressMaker(MEMORY_MAPPER_WRAPPER_FOR_MEMORY_WRITE TypeOfWrite, UINT64 DestinationAddr, PCR3_TYPE TargetProcessCr3, UINT32 TargetProcessId)
Decides about making the address and converting the address to physical address based on the passed p...
Definition MemoryMapper.c:1212
_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemorySafeByPte(PVOID SourceVA, PHYSICAL_ADDRESS PaAddressToWrite, SIZE_T SizeToWrite, UINT64 PteVaAddress, UINT64 MappingVa, BOOLEAN InvalidateVpids)
Write memory safely by mapping the buffer using PTE.
Definition MemoryMapper.c:848

◆ MemoryMapperWriteMemorySafeWrapperAddressMaker()

_Use_decl_annotations_ UINT64 MemoryMapperWriteMemorySafeWrapperAddressMaker ( MEMORY_MAPPER_WRAPPER_FOR_MEMORY_WRITE TypeOfWrite,
UINT64 DestinationAddr,
PCR3_TYPE TargetProcessCr3,
UINT32 TargetProcessId )

Decides about making the address and converting the address to physical address based on the passed parameters.

Parameters
TypeOfWriteType of memory write
DestinationAddrDestination Address
TargetProcessCr3The process CR3 (might be null)
TargetProcessIdThe process PID (might be null)
Returns
UINT64 returns the target physical address and NULL if it fails
1216{
1217 PHYSICAL_ADDRESS PhysicalAddress = {0};
1218
1219 switch (TypeOfWrite)
1220 {
1222
1223 PhysicalAddress.QuadPart = DestinationAddr;
1224
1225 break;
1226
1228
1229 if (TargetProcessId == NULL_ZERO)
1230 {
1231 PhysicalAddress.QuadPart = VirtualAddressToPhysicalAddress((PVOID)DestinationAddr);
1232 }
1233 else
1234 {
1235 PhysicalAddress.QuadPart = VirtualAddressToPhysicalAddressByProcessId((PVOID)DestinationAddr, TargetProcessId);
1236 }
1237
1238 break;
1239
1241
1242 if (TargetProcessCr3 == NULL || TargetProcessCr3->Flags == NULL64_ZERO)
1243 {
1244 PhysicalAddress.QuadPart = VirtualAddressToPhysicalAddress((PVOID)DestinationAddr);
1245 }
1246 else
1247 {
1248 PhysicalAddress.QuadPart = VirtualAddressToPhysicalAddressByProcessCr3((PVOID)DestinationAddr, *TargetProcessCr3);
1249 }
1250
1251 break;
1252
1253 default:
1254 return NULL64_ZERO;
1255
1256 break;
1257 }
1258
1259 return PhysicalAddress.QuadPart;
1260}
_Use_decl_annotations_ UINT64 VirtualAddressToPhysicalAddressByProcessId(PVOID VirtualAddress, UINT32 ProcessId)
Converts Virtual Address to Physical Address based on a specific process id's kernel cr3.
Definition Conversion.c:171
_Use_decl_annotations_ UINT64 VirtualAddressToPhysicalAddressByProcessCr3(PVOID VirtualAddress, CR3_TYPE TargetCr3)
Converts Virtual Address to Physical Address based on a specific process's kernel cr3.
Definition Conversion.c:215
@ MEMORY_MAPPER_WRAPPER_WRITE_VIRTUAL_MEMORY_UNSAFE
Definition MemoryMapper.h:48

◆ MemoryMapperWriteMemoryUnsafe()

_Use_decl_annotations_ BOOLEAN MemoryMapperWriteMemoryUnsafe ( UINT64 Destination,
PVOID Source,
SIZE_T SizeToWrite,
UINT32 TargetProcessId )

Write memory safely by mapping the buffer (It's a wrapper)

this function should not be called from vmx-root mode

Parameters
DestinationDestination Virtual Address
SourceSource Virtual Address
SizeToWriteSize
TargetProcessIdTarget Process Id
Returns
BOOLEAN returns TRUE if it was successful and FALSE if there was error
1412{
1414 Destination,
1415 (UINT64)Source,
1416 SizeToWrite,
1417 NULL,
1418 TargetProcessId);
1419}