updated KernelWriteProtect project to include PFN remapping technique

This commit is contained in:
winterknife
2026-06-07 09:24:34 -04:00
parent 9d887288d4
commit 5013204277
5 changed files with 309 additions and 60 deletions
+13 -2
View File
@@ -7,7 +7,7 @@
//
// Modifications:
// 2026-05-12 Created
// 2026-05-15 Updated
// 2026-06-03 Updated
// ========================================================================
// ========================================================================
@@ -87,7 +87,7 @@ EXTERN_C DECLSPEC_NOINLINE VOID __stdcall copy_memory_cr0_wp(
_In_ DWORD_PTR dwptrLength
);
/// @brief Copies the contents of a source memory block to a destination memory block with write protect bypass using double mapping
/// @brief Copies the contents of a source memory block to a destination memory block with write protect bypass using MDL double mapping
/// @param pDestination Pointer to the destination memory block to copy the bytes to
/// @param pcSource Pointer to the source memory block to copy the bytes from
/// @param dwptrLength Number of bytes to copy from the source to the destination
@@ -109,4 +109,15 @@ EXTERN_C DECLSPEC_NOINLINE VOID __stdcall copy_memory_pte(
_In_ DWORD_PTR dwptrLength
);
/// @brief Copies the contents of a source memory block to a destination memory block with write protect bypass using PFN remapping
/// @param pDestination Pointer to the destination memory block to copy the bytes to
/// @param pcSource Pointer to the source memory block to copy the bytes from
/// @param dwptrLength Number of bytes to copy from the source to the destination
_IRQL_requires_max_(APC_LEVEL)
EXTERN_C DECLSPEC_NOINLINE VOID __stdcall copy_memory_page_remapping(
_Out_writes_bytes_all_(dwptrLength) VOID* pDestination,
_In_reads_bytes_(dwptrLength) CONST VOID* pcSource,
_In_ DWORD_PTR dwptrLength
);
#pragma endregion
@@ -57,7 +57,7 @@
<WholeProgramOptimization>true</WholeProgramOptimization>
</ClCompile>
<Link>
<AdditionalOptions>/EMITPOGOPHASEINFO /NOVCFEATURE /NOCOFFGRPINFO /FILEALIGN:0x200 /PDBALTPATH:$(ProjectName).pdb /Brepro /RELEASE /EMITTOOLVERSIONINFO:NO %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>/EMITPOGOPHASEINFO /NOVCFEATURE /NOCOFFGRPINFO /FILEALIGN:0x200 /PDBALTPATH:$(ProjectName).pdb /Brepro /RELEASE /EMITTOOLVERSIONINFO:NO /DRIVER:WDM %(AdditionalOptions)</AdditionalOptions>
<EntryPointSymbol />
<AdditionalDependencies>Ntoskrnl.lib</AdditionalDependencies>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
+49 -34
View File
@@ -2,7 +2,7 @@
## Version
- `v2.0.0`
- `v3.0.0`
## Brief
@@ -12,55 +12,63 @@
- `CPL: 0`
- `OS: Windows`
- `Language: C`
- Sample code that demonstrates three techniques for writing into read-only pages in kernel space using `CR0.WP` manipulation, `MDL` double mapping, and `PTE` manipulation
- Sample code that demonstrates four techniques for writing into read-only pages in kernel space using `CR0.WP` manipulation, `MDL` double mapping, `PTE` manipulation, and `PFN` remapping.
## Usage
```
0: kd> vertarget
1: kd> vertarget
Windows 10 Kernel Version 26100 MP (2 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Edition build lab: 26100.1.amd64fre.ge_release.240331-1435
Kernel base = 0xfffff801`ece00000 PsLoadedModuleList = 0xfffff801`edcf5150
Debug session time: Mon May 18 11:32:44.468 2026 (UTC - 4:00)
System Uptime: 0 days 1:46:43.304
Kernel base = 0xfffff801`cb400000 PsLoadedModuleList = 0xfffff801`cc2f52d0
Debug session time: Fri Jun 5 15:50:12.936 2026 (UTC - 4:00)
System Uptime: 0 days 0:01:50.980
0: kd> g
1: kd> g
KDFILES: Replacing '\??\C:\pub\KernelWriteProtect.sys' with 'C:\Users\winterknife\Desktop\CNO-Programs\EVENSTAR\KernelWriteProtect\Bin\x64\KernelWriteProtect.sys'. File size 7KB.
KdPullRemoteFile(FFFFAD0304FC5040): About to overwrite \??\C:\pub\KernelWriteProtect.sys and preallocate to 1a60
KdPullRemoteFile(FFFFAD0304FC5040): Return from ZwCreateFile with status 0
..
[DBG]: +++ KernelWriteProtect.sys Loaded +++
[DBG]: KernelWriteProtect.sys Built May 18 2026 11:31:17
[DBG]: KernelWriteProtect: DriverObject = FFFFBD0FF0496E20
[DBG]: KernelWriteProtect.sys Built Jun 5 2026 15:23:55
[DBG]: KernelWriteProtect: DriverObject = FFFFAD0305316E10
[DBG]: KernelWriteProtect: RegistryPath = \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\KernelWriteProtect
[DBG]: --- KernelWriteProtect.sys Unloaded ---
[DBG]: KernelWriteProtect: g_dwProtectedValue KVA = 0xFFFFF801625A4000
[DBG]: KernelWriteProtect: g_dwProtectedValue original contents = 0xDEADBEEF
[DBG]: KernelWriteProtect: g_dwProtectedValue protected by static KDP.
Break instruction exception - code 80000003 (first chance)
*******************************************************************************
* *
* You are seeing this message because you pressed either *
* CTRL+C (if you run console kernel debugger) or, *
* CTRL+BREAK (if you run GUI kernel debugger), *
* on your debugger machine's keyboard. *
* *
* THIS IS NOT A BUG OR A SYSTEM CRASH *
* *
* If you did not intend to break into the debugger, press the "g" key, then *
* press the "Enter" key now. This message might immediately reappear. If it *
* does, press "g" and "Enter" again. *
* *
*******************************************************************************
nt!DbgBreakPointWithStatus:
fffff801`ed2fb1b0 cc int 3
KernelWriteProtect_fffff801625a0000!DriverEntry+0xe0:
fffff801`625a50e0 cc int 3
0: kd> !pte 0xFFFFF78000000738
VA fffff78000000738
PXE at FFFFF2793C9E4F78 PPE at FFFFF2793C9EF000 PDE at FFFFF2793DE00000 PTE at FFFFF27BC0000000
contains 0000000000286063 contains 0000000000285063 contains 0000000000284063 contains 8A00000000283121
pfn 286 ---DA--KWEV pfn 285 ---DA--KWEV pfn 284 ---DA--KWEV pfn 283 -G--A--KR-V
1: kd> !pte g_dwProtectedValue
VA fffff801625a4000
PXE at FFFFE673399CCF80 PPE at FFFFE673399F0028 PDE at FFFFE6733E005890 PTE at FFFFE67C00B12D20
contains 00000000001D0063 contains 00000000001CF063 contains 0A0000011169D863 contains 89000001C0FDF121
pfn 1d0 ---DA--KWEV pfn 1cf ---DA--KWEV pfn 11169d ---DA--KWEV pfn 1c0fdf -G--A--KR-V
0: kd> db 0xFFFFF78000000738 LC
fffff780`00000738 41 41 41 41 41 41 41 41-41 41 41 41 AAAAAAAAAAAA
1: kd> dd g_dwProtectedValue L1
fffff801`625a4000 deadbeef
1: kd> g
[DBG]: KernelWriteProtect: g_dwProtectedValue modified contents = 0x41414141
Break instruction exception - code 80000003 (first chance)
KernelWriteProtect_fffff801625a0000!DriverEntry+0x10a:
fffff801`625a510a cc int 3
1: kd> !pte g_dwProtectedValue
VA fffff801625a4000
PXE at FFFFE673399CCF80 PPE at FFFFE673399F0028 PDE at FFFFE6733E005890 PTE at FFFFE67C00B12D20
contains 00000000001D0063 contains 00000000001CF063 contains 0A0000011169D863 contains 89000001BADC3121
pfn 1d0 ---DA--KWEV pfn 1cf ---DA--KWEV pfn 11169d ---DA--KWEV pfn 1badc3 -G--A--KR-V
1: kd> dd g_dwProtectedValue L1
fffff801`625a4000 41414141
```
## Tested OS Versions
- `Windows 11 25H2 Build 26200 Revision 8246 64-bit`
- `Windows 11 25H2 Build 26200 Revision 8457 64-bit`
## References
@@ -70,3 +78,10 @@ fffff780`00000738 41 41 41 41 41 41 41 41-41 41 41 41 AAAAAAAAAAAA
4. [kernelhook](https://github.com/adrianyy/kernelhook)
5. [Exploit Development: Leveraging Page Table Entries for Windows Kernel Exploitation](https://connormcgarr.github.io/pte-overwrites/)
6. [g_CiOptions in a Virtualized World](https://trustedsec.com/blog/g_cioptions-in-a-virtualized-world)
7. [Melting Down PatchGuard: Leveraging KPTI to Bypass Kernel Patch Protection](https://www.fortinet.com/blog/threat-research/melting-down-patchguard-leveraging-kpi-to-bypass-kernel-patch-protection)
8. [The Swan Song for Driver Signature Enforcement Tampering](https://www.fortinet.com/blog/threat-research/driver-signature-enforcement-tampering)
9. [Code Execution against Windows HVCI](https://datafarm-cybersecurity.medium.com/code-execution-against-windows-hvci-f617570e9df0)
10. [Intel VT-rp - Part 1. remapping attack and HLAT](https://tandasat.github.io/blog/2023/07/05/intel-vt-rp-part-1.html)
11. [Intel VT-rp - Part 2. paging-write and guest-paging verification](https://tandasat.github.io/blog/2023/07/31/intel-vt-rp-part-2.html)
12. [HEXACON2023 - Bypassing the HVCI memory protection by Viviane Zwanger and Henning Braun](https://www.youtube.com/watch?v=WWvd2_jd0ZI)
13. [BusterCall](https://github.com/zer0condition/BusterCall)
+41 -20
View File
@@ -7,7 +7,7 @@
//
// Modifications:
// 2026-04-13 Created
// 2026-05-16 Updated
// 2026-06-05 Updated
// ========================================================================
// ========================================================================
@@ -17,24 +17,24 @@
#include "../Inc/Common.h"
#include "../Inc/WriteProtectBypass.h"
// ========================================================================
// Globals
// ========================================================================
#pragma region GLOBALS
// RO global variable
#pragma section(".rodata", read)
__declspec(allocate(".rodata")) DWORD g_dwProtectedValue = 0xDEADBEEF;
#pragma endregion
// ========================================================================
// Routines
// ========================================================================
#pragma region ROUTINES
/// @brief DRIVER_UNLOAD callback routine that gets called to uninitialize the driver when it is unloaded
/// @param pDriverObject Pointer to DRIVER_OBJECT structure representing the driver's driver object
_IRQL_requires_(PASSIVE_LEVEL)
EXTERN_C __declspec(code_seg("PAGE")) VOID __stdcall driver_unload(
_In_ PDRIVER_OBJECT pDriverObject
) {
// Suppress W4 warning - C4100
UNREFERENCED_PARAMETER(pDriverObject);
DEBUG_PRINT("--- %s.sys Unloaded ---\n", __MODULE__);
}
/// @brief DRIVER_INITIALIZE callback routine that gets called to initialize the driver when it is loaded
/// @param pDriverObject Pointer to DRIVER_OBJECT structure representing the driver's driver object
/// @param puncRegistryPath Pointer to UNICODE_STRING structure specifying the path to the driver's registry key
@@ -49,15 +49,36 @@ EXTERN_C __declspec(code_seg("INIT")) NTSTATUS __stdcall DriverEntry(
DEBUG_PRINT("%s: DriverObject = %p\n", __MODULE__, pDriverObject);
DEBUG_PRINT("%s: RegistryPath = %wZ\n", __MODULE__, puncRegistryPath);
// Set routine to be called on driver unload
pDriverObject->DriverUnload = static_cast<PDRIVER_UNLOAD>(driver_unload);
// This driver cannot be unloaded
// /DRIVER:WDM linker switch + no DRIVER_UNLOAD routine + no MM_PROTECT_DRIVER_SECTION_ALLOW_UNLOAD flag
// Write data into RO _KUSER_SHARED_DATA structure
DEBUG_PRINT("%s: g_dwProtectedValue KVA = 0x%p\n", __MODULE__, &g_dwProtectedValue);
DEBUG_PRINT("%s: g_dwProtectedValue original contents = 0x%I32X\n", __MODULE__, ReadULongNoFence(&g_dwProtectedValue));
// Mark the guest physical page containing g_dwProtectedValue as RO in the SLAT entry
NTSTATUS status = MmProtectDriverSection(&g_dwProtectedValue, 0, 0);
if (!NT_SUCCESS(status)) {
DEBUG_PRINT("%s: MmProtectDriverSection error = 0x%08X\n", __MODULE__, status);
return status;
}
DEBUG_PRINT("%s: g_dwProtectedValue protected by static KDP.\n", __MODULE__);
__debugbreak();
// Corrupt RO data page
BYTE byarrPayload[] = { 0x41, 0x41, 0x41, 0x41 };
QWORD qwKuserSharedData = 0xFFFFF78000000000ULL;
copy_memory_cr0_wp(reinterpret_cast<PVOID>(qwKuserSharedData + 0x738ULL), byarrPayload, sizeof(byarrPayload));
copy_memory_double_mapping(reinterpret_cast<PVOID>(qwKuserSharedData + 0x73CULL), byarrPayload, sizeof(byarrPayload));
copy_memory_pte(reinterpret_cast<PVOID>(qwKuserSharedData + 0x740ULL), byarrPayload, sizeof(byarrPayload));
//copy_memory_cr0_wp(&g_dwProtectedValue, byarrPayload, sizeof(byarrPayload));
//DEBUG_PRINT("%s: g_dwProtectedValue modified contents = 0x%I32X\n", __MODULE__, ReadULongNoFence(&g_dwProtectedValue));
//copy_memory_double_mapping(&g_dwProtectedValue, byarrPayload, sizeof(byarrPayload));
//DEBUG_PRINT("%s: g_dwProtectedValue modified contents = 0x%I32X\n", __MODULE__, ReadULongNoFence(&g_dwProtectedValue));
//copy_memory_pte(&g_dwProtectedValue, byarrPayload, sizeof(byarrPayload));
//DEBUG_PRINT("%s: g_dwProtectedValue modified contents = 0x%I32X\n", __MODULE__, ReadULongNoFence(&g_dwProtectedValue));
copy_memory_page_remapping(&g_dwProtectedValue, byarrPayload, sizeof(byarrPayload));
DEBUG_PRINT("%s: g_dwProtectedValue modified contents = 0x%I32X\n", __MODULE__, ReadULongNoFence(&g_dwProtectedValue));
__debugbreak();
return STATUS_SUCCESS;
}
+204 -2
View File
@@ -5,11 +5,11 @@
//
// Description: Source file that contains the necessary routines to bypass
// the Write Protect (WP) mitigation to allow supervisor-level procedures
// to write into read-only pages
// to write into read-only pages in kernel space
//
// Modifications:
// 2026-05-12 Created
// 2026-05-23 Updated
// 2026-06-06 Updated
// ========================================================================
// ========================================================================
@@ -318,4 +318,206 @@ cleanup:
KeLowerIrql(kirqlOld);
}
_Use_decl_annotations_
VOID __stdcall copy_memory_page_remapping(
VOID* pDestination,
CONST VOID* pcSource,
DWORD_PTR dwptrLength
) {
// Init local variables
PVOID pNtoskrnl = nullptr;
PVOID pMmGetVirtualForPhysical = nullptr;
DWORD dwOffsetImm64 = 0;
QWORD qwMmPteBase = 0;
PMMPTE_HARDWARE pMmpteHardwarePte = nullptr;
PMMPTE_HARDWARE pMmpteHardwarePde = nullptr;
PMMPTE_HARDWARE pMmpteHardwarePpe = nullptr;
PMMPTE_HARDWARE pMmpteHardwarePxe = nullptr;
PVOID pReserved = nullptr;
PHYSICAL_ADDRESS physicalAddressLow; __stosb(reinterpret_cast<PUCHAR>(&physicalAddressLow), 0, sizeof(PHYSICAL_ADDRESS));
PHYSICAL_ADDRESS physicalAddressHigh; __stosb(reinterpret_cast<PUCHAR>(&physicalAddressHigh), 0, sizeof(PHYSICAL_ADDRESS));
PHYSICAL_ADDRESS physicalAddressSkipBytes; __stosb(reinterpret_cast<PUCHAR>(&physicalAddressSkipBytes), 0, sizeof(PHYSICAL_ADDRESS));
PMDL pMdl = nullptr;
PVOID pPage = nullptr;
NTSTATUS status = STATUS_SUCCESS;
KIRQL kirqlOld = 0;
BOOLEAN bIrqlRaised = false;
MMPTE_HARDWARE mmpteHardwareNew; __stosb(reinterpret_cast<PUCHAR>(&mmpteHardwareNew), 0, sizeof(MMPTE_HARDWARE));
MMPTE_HARDWARE mmpteHardwareOld; __stosb(reinterpret_cast<PUCHAR>(&mmpteHardwareOld), 0, sizeof(MMPTE_HARDWARE));
BOOLEAN bPfnSwapped = false;
// Check if the write will span a page boundary
if (ADDRESS_AND_SIZE_TO_SPAN_PAGES(pDestination, dwptrLength) > 1) {
goto cleanup;
}
// Get the nt image base address
RtlPcToFileHeader(reinterpret_cast<PVOID>(RtlFindExportedRoutineByName), &pNtoskrnl);
if (pNtoskrnl == nullptr) {
goto cleanup;
}
// Get the KVA of nt!MmGetVirtualForPhysical
pMmGetVirtualForPhysical = RtlFindExportedRoutineByName(pNtoskrnl, "MmGetVirtualForPhysical");
if (pMmGetVirtualForPhysical == nullptr) {
goto cleanup;
}
/*
0: kd> uf nt!MmGetVirtualForPhysical
nt!MmGetVirtualForPhysical:
fffff803`8ec6e980 488bc1 mov rax,rcx
fffff803`8ec6e983 48c1e80c shr rax,0Ch
fffff803`8ec6e987 488d1440 lea rdx,[rax+rax*2]
fffff803`8ec6e98b 4803d2 add rdx,rdx
fffff803`8ec6e98e 48b80800000080b1ffff mov rax,0FFFFB18000000008h
fffff803`8ec6e998 488b04d0 mov rax,qword ptr [rax+rdx*8]
fffff803`8ec6e99c 48c1e019 shl rax,19h
fffff803`8ec6e9a0 48ba0000000080aeffff mov rdx,0FFFFAE8000000000h
fffff803`8ec6e9aa 48c1e219 shl rdx,19h
fffff803`8ec6e9ae 81e1ff0f0000 and ecx,0FFFh
fffff803`8ec6e9b4 482bc2 sub rax,rdx
fffff803`8ec6e9b7 48c1f810 sar rax,10h
fffff803`8ec6e9bb 4803c1 add rax,rcx
fffff803`8ec6e9be c3 ret
*/
// This is not the correct way to find nt!MmPteBase, use nt!KdDebuggerDataBlock
dwOffsetImm64 = 0x22UL;
// Get the KVA of nt!MmPteBase
// Starting from 64-bit Windows 10 1607 Anniversary Update (RS1) Build 14393, the PML4 table auto-entry index is randomized at boot time as part of KASLR (earlier, index fixed at 0x1ED)
qwMmPteBase = *reinterpret_cast<PQWORD>(static_cast<PUCHAR>(pMmGetVirtualForPhysical) + dwOffsetImm64);
// Compute the KVA of the PTE for the write address
// BMI1 is only available since Haswell Intel microarchitecture (2013)
/*
0: kd> uf nt!MiGetPteAddress
nt!MiGetPteAddress:
fffff803`8ea376c0 48c1e909 shr rcx,9
fffff803`8ea376c4 48b8f8ffffff7f000000 mov rax,7FFFFFFFF8h
fffff803`8ea376ce 4823c8 and rcx,rax
fffff803`8ea376d1 48b80000000080aeffff mov rax,0FFFFAE8000000000h
fffff803`8ea376db 4803c1 add rax,rcx
fffff803`8ea376de c3 ret
*/
pMmpteHardwarePte = reinterpret_cast<PMMPTE_HARDWARE>(_andn_u64(0x7ULL, qwMmPteBase + __ull_rshift(__ll_lshift(reinterpret_cast<QWORD>(pDestination), 0x10), 0x19)));
// Compute the KVA of the PDE for the write address
/*
0: kd> uf nt!MiGetPdeAddress
nt!MiGetPdeAddress:
fffff803`8ea12470 48c1e912 shr rcx,12h
fffff803`8ea12474 81e1f8ffff3f and ecx,3FFFFFF8h
fffff803`8ea1247a 48b800000040d7aeffff mov rax,0FFFFAED740000000h
fffff803`8ea12484 4803c1 add rax,rcx
fffff803`8ea12487 c3 ret
*/
pMmpteHardwarePde = reinterpret_cast<PMMPTE_HARDWARE>(_andn_u64(0x7ULL, qwMmPteBase + __ull_rshift(__ll_lshift(reinterpret_cast<QWORD>(pMmpteHardwarePte), 0x10), 0x19)));
// Compute the KVA of the PDPTE for the write address
pMmpteHardwarePpe = reinterpret_cast<PMMPTE_HARDWARE>(_andn_u64(0x7ULL, qwMmPteBase + __ull_rshift(__ll_lshift(reinterpret_cast<QWORD>(pMmpteHardwarePde), 0x10), 0x19)));
// Compute the KVA of the PML4E for the write address
pMmpteHardwarePxe = reinterpret_cast<PMMPTE_HARDWARE>(_andn_u64(0x7ULL, qwMmPteBase + __ull_rshift(__ll_lshift(reinterpret_cast<QWORD>(pMmpteHardwarePpe), 0x10), 0x19)));
// Reserve a memory buffer in KVAS using system PTEs
pReserved = MmAllocateMappingAddressEx(PAGE_SIZE, __POOLTAG__, 0);
if (pReserved == nullptr) {
goto cleanup;
}
// Allocate nonpaged physical memory pages to build an MDL
// NOTE: When HVCI is enabled, dynamic allocation of executable memory is no longer possible
physicalAddressHigh.QuadPart = MAXULONG64;
pMdl = MmAllocatePagesForMdlEx(physicalAddressLow, physicalAddressHigh, physicalAddressSkipBytes, PAGE_SIZE, MmCached, MM_ALLOCATE_FULLY_REQUIRED);
if (pMdl == nullptr) {
goto cleanup;
}
// Map the MDL in the reserved memory buffer
pPage = MmMapLockedPagesWithReservedMapping(pReserved, __POOLTAG__, pMdl, MmCached);
if (pPage == nullptr) {
goto cleanup;
}
// Set the protection type for the mapping to RW
status = MmProtectMdlSystemAddress(pMdl, PAGE_READWRITE);
if (!NT_SUCCESS(status)) {
goto cleanup;
}
// Clone the original RO page into the newly allocated 4 KB RW page
__movsb(static_cast<PUCHAR>(pPage), static_cast<UCHAR const*>(PAGE_ALIGN(pDestination)), PAGE_SIZE);
// Write into RW page
__movsb(static_cast<PUCHAR>(pPage) + BYTE_OFFSET(pDestination), static_cast<UCHAR const*>(pcSource), dwptrLength);
// Raise the Interrupt Request Level (IRQL) of the current processor to DISPATCH_LEVEL
// This will prevent the thread scheduler from preempting the current thread
kirqlOld = KeRaiseIrqlToDpcLevel();
bIrqlRaised = true;
// Check if the PML4E is valid
if (!pMmpteHardwarePxe->Valid) {
goto cleanup;
}
// Check if the PDPTE is valid
if (!pMmpteHardwarePpe->Valid) {
goto cleanup;
}
// Check if the PDE is valid
// We do not support large pages at the moment
if (!pMmpteHardwarePde->Valid || pMmpteHardwarePde->LargePage) {
goto cleanup;
}
// Check if the PTE is valid
if (!pMmpteHardwarePte->Valid) {
goto cleanup;
}
// Swap the PFN in the PTE that maps the original RO page with the PFN in the PTE that maps the modified RW page
// WARNING: If the code / data page is protected by HLAT then the paging structure will be managed by the hypervisor
// WARNING: HyperGuard / Secure Kernel Patch Guard (SKPG) runs checks at random intervals and will bugcheck unless the original PFN is restored
mmpteHardwareOld = *pMmpteHardwarePte;
mmpteHardwareNew = mmpteHardwareOld;
mmpteHardwareNew.PageFrameNumber = MmGetMdlPfnArray(pMdl)[0];
if (_InterlockedCompareExchange64(reinterpret_cast<LONG64 volatile*>(pMmpteHardwarePte), *reinterpret_cast<LONG64*>(&mmpteHardwareNew), *reinterpret_cast<LONG64*>(&mmpteHardwareOld)) != *reinterpret_cast<LONG64*>(&mmpteHardwareOld)) {
goto cleanup;
}
bPfnSwapped = true;
// Invalidate any Translation Lookaside Buffer (TLB) entries for the target page
// Remember to flush the TLB on all logical processors by sending an IPI
__invlpg(pDestination); // INVLPG - Invalidate TLB Entries
// Cleanup
cleanup:
// Restore the original IRQL of the current processor
if (bIrqlRaised)
KeLowerIrql(kirqlOld);
// Check if the PFN swapping wasn't successful
// Note that there is a memory leak on the success path
if (!bPfnSwapped) {
// Release the mapping
if (pPage)
MmUnmapReservedMapping(pPage, __POOLTAG__, pMdl);
// Free the physical page described by the MDL
if (pMdl)
MmFreePagesFromMdl(pMdl);
// Release the MDL
if (pMdl)
ExFreePool(pMdl);
// Free the reserved memory buffer
if (pReserved)
MmFreeMappingAddress(pReserved, __POOLTAG__);
}
}
#pragma endregion