Browse Source

init commit

master
_xeroxz 2 years ago
parent
commit
0c5b29f708
  1. BIN
      img/kmem-icon.png
  2. 22
      kmem.sln
  3. 3
      kmem/icon.rc
  4. 107
      kmem/kmem.vcxproj
  5. 64
      kmem/kmem.vcxproj.filters
  6. 11
      kmem/kmem.vcxproj.user
  7. 120
      kmem/kmem_ctx/kmem_ctx.cpp
  8. 17
      kmem/kmem_ctx/kmem_ctx.hpp
  9. 77
      kmem/main.cpp
  10. 480
      kmem/mem_ctx/mem_ctx.cpp
  11. 86
      kmem/mem_ctx/mem_ctx.hpp
  12. BIN
      kmem/small.ico
  13. 247
      kmem/util/loadup.hpp
  14. 193
      kmem/util/nt.hpp
  15. 323
      kmem/util/util.hpp
  16. 2242
      kmem/vdm/raw_driver.hpp
  17. 142
      kmem/vdm/vdm.hpp
  18. 123
      kmem/vdm_ctx/vdm_ctx.cpp
  19. 116
      kmem/vdm_ctx/vdm_ctx.hpp

BIN
img/kmem-icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

22
kmem.sln

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30503.244
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kmem", "kmem\kmem.vcxproj", "{ED392663-3AF3-40DE-8AC7-2F373B3E9B45}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ED392663-3AF3-40DE-8AC7-2F373B3E9B45}.Release|x64.ActiveCfg = Release|x64
{ED392663-3AF3-40DE-8AC7-2F373B3E9B45}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {31E8D06F-582D-4DDC-88A4-8FE8CBEC5EDF}
EndGlobalSection
EndGlobal

3
kmem/icon.rc

@ -0,0 +1,3 @@
// Icon Resource Definition
#define MAIN_ICON 102
MAIN_ICON ICON "small.ico"

107
kmem/kmem.vcxproj

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{ed392663-3af3-40de-8ac7-2f373b3e9b45}</ProjectGuid>
<RootNamespace>nasainjector</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>kmem</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<Optimization>Custom</Optimization>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<Optimization>Custom</Optimization>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="kmem_ctx\kmem_ctx.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="mem_ctx\mem_ctx.cpp" />
<ClCompile Include="vdm_ctx\vdm_ctx.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="kmem_ctx\kmem_ctx.hpp" />
<ClInclude Include="mem_ctx\mem_ctx.hpp" />
<ClInclude Include="util\loadup.hpp" />
<ClInclude Include="util\nt.hpp" />
<ClInclude Include="util\util.hpp" />
<ClInclude Include="vdm\raw_driver.hpp" />
<ClInclude Include="vdm\vdm.hpp" />
<ClInclude Include="vdm_ctx\vdm_ctx.hpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="icon.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

64
kmem/kmem.vcxproj.filters

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Header Files\vdm">
<UniqueIdentifier>{b197b9bf-8ab7-40c3-89e0-ad2ac4a211ab}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\util">
<UniqueIdentifier>{565c24cf-6d76-4715-9d8c-f35b17ee0ec6}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vdm_ctx\vdm_ctx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mem_ctx\mem_ctx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="kmem_ctx\kmem_ctx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="vdm\raw_driver.hpp">
<Filter>Header Files\vdm</Filter>
</ClInclude>
<ClInclude Include="vdm\vdm.hpp">
<Filter>Header Files\vdm</Filter>
</ClInclude>
<ClInclude Include="vdm_ctx\vdm_ctx.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="util\loadup.hpp">
<Filter>Header Files\util</Filter>
</ClInclude>
<ClInclude Include="util\nt.hpp">
<Filter>Header Files\util</Filter>
</ClInclude>
<ClInclude Include="util\util.hpp">
<Filter>Header Files\util</Filter>
</ClInclude>
<ClInclude Include="mem_ctx\mem_ctx.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="kmem_ctx\kmem_ctx.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="icon.rc">
<Filter>Header Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

11
kmem/kmem.vcxproj.user

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments>--pid 12116</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>--pid 69</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

120
kmem/kmem_ctx/kmem_ctx.cpp

@ -0,0 +1,120 @@
#include "kmem_ctx.hpp"
namespace nasa
{
kmem_ctx::kmem_ctx(vdm::vdm_ctx* vdm)
: vdm(vdm)
{
const auto runtime_broker_pid =
util::start_runtime_broker();
zombie(runtime_broker_pid);
const auto runtime_broker_peproc =
vdm->get_peprocess(runtime_broker_pid);
set_process_name(runtime_broker_peproc, L"/proc/kmem");
mem_ctx runtime_ctx(*vdm, runtime_broker_pid);
const auto pml4 =
reinterpret_cast<ppml4e>(
runtime_ctx.set_page(
runtime_ctx.get_dirbase()));
// shoot the legs off the table, make it to do a back flip...
// (aka put kernel pml4e's into usermode/below MmHighestUserAddress so NtReadVirtualMemory
// and NtWriteVirtualMemory/all winapis will work)...
memcpy(pml4, pml4 + 255, 256 * sizeof pml4e);
}
auto kmem_ctx::translate(std::uintptr_t kva) -> std::uintptr_t
{
virt_addr_t old_addr{ reinterpret_cast<void*>(kva) };
virt_addr_t new_addr{ NULL };
new_addr.pml4_index = old_addr.pml4_index - 255;
new_addr.pdpt_index = old_addr.pdpt_index;
new_addr.pd_index = old_addr.pd_index;
new_addr.pt_index = old_addr.pt_index;
return reinterpret_cast<std::uintptr_t>(new_addr.value);
}
auto kmem_ctx::get_handle()->HANDLE
{
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, util::get_pid("/proc/kmem"));
}
void kmem_ctx::zombie(std::uint32_t pid) const
{
// zombie the the process by incrementing an exit counter
// then calling TerminateProcess so the process never closes...
const auto runtime_broker_peproc =
reinterpret_cast<std::uintptr_t>(
vdm->get_peprocess(pid));
static const auto inc_ref_counter =
util::get_kmodule_export(
"ntoskrnl.exe",
"PsAcquireProcessExitSynchronization"
);
const auto result =
vdm->syscall<NTSTATUS(*)(std::uintptr_t)>(
inc_ref_counter, runtime_broker_peproc);
const auto handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
TerminateProcess(handle, NULL);
CloseHandle(handle);
}
bool kmem_ctx::set_process_name(PEPROCESS peproc, const wchar_t* new_name)
{
static const auto process_image_name =
reinterpret_cast<std::uintptr_t>(
util::get_kmodule_export(
"ntoskrnl.exe", "SeLocateProcessImageName"));
if (!process_image_name)
return false;
// SeLocateProcessImageName --> PsGetAllocatedFullProcessImageNameEx
// PAGE : 00000001406B1A50 SeLocateProcessImageName proc near
// PAGE : 00000001406B1A50 48 83 EC 28 sub rsp, 28h
// PAGE : 00000001406B1A54 E8 0B 00 00 00 call PsGetAllocatedFullProcessImageNameEx <====== + 5
// PAGE : 00000001406B1A59 48 83 C4 28 add rsp, 28h
// PAGE : 00000001406B1A5D C3 retn
// PAGE : 00000001406B1A5D SeLocateProcessImageName endp
const auto get_process_name =
(process_image_name + 9 + vdm->rkm<std::uint32_t>(process_image_name + 5)); // <====== + 5
// PAGE : 00000001406B1A64 48 83 EC 28 sub rsp, 28h
// PAGE : 00000001406B1A68 48 83 B9 10 07 00 00 00 cmp qword ptr[rcx + 710h], 0
// PAGE : 00000001406B1A70 B8 25 02 00 C0 mov eax, 0C0000225h
// PAGE : 00000001406B1A75 0F 85 0B E9 10 00 jnz loc_1407C0386
// PAGE : 00000001406B1A7B 48 83 B9 68 04 00 00 00 cmp qword ptr[rcx + 468h], 0 <===== + 26
const auto process_name_idx =
vdm->rkm<std::uint32_t>(get_process_name + 26); // <===== + 26
// _SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo
// _SE_AUDIT_PROCESS_CREATION_INFO --> POBJECT_NAME_INFORMATION == PUNICODE_STRING...
const auto unicode_string_ptr =
vdm->rkm<std::uintptr_t>(
reinterpret_cast<std::uintptr_t>(peproc) + process_name_idx);
if (!unicode_string_ptr)
return false;
auto process_unicode_str =
vdm->rkm<UNICODE_STRING>(unicode_string_ptr);
if (!process_unicode_str.Buffer)
return false;
// set new name...
vdm->wkm((void*)process_unicode_str.Buffer, (void*)new_name, std::wcslen(new_name) * sizeof(wchar_t));
// set new unicode string info...
process_unicode_str.Length = std::wcslen(new_name) * sizeof(wchar_t);
process_unicode_str.MaximumLength = std::wcslen(new_name) * sizeof(wchar_t);
vdm->wkm<UNICODE_STRING>(unicode_string_ptr, process_unicode_str);
return true;
}
}

17
kmem/kmem_ctx/kmem_ctx.hpp

@ -0,0 +1,17 @@
#pragma once
#include "../mem_ctx/mem_ctx.hpp"
namespace nasa
{
class kmem_ctx
{
public:
kmem_ctx(vdm::vdm_ctx* vdm);
static auto get_handle()->HANDLE;
static auto translate(std::uintptr_t kva)->std::uintptr_t;
private:
void zombie(std::uint32_t pid) const;
bool set_process_name(PEPROCESS peproc, const wchar_t* new_name);
vdm::vdm_ctx* vdm;
};
}

77
kmem/main.cpp

@ -0,0 +1,77 @@
#include "kmem_ctx/kmem_ctx.hpp"
int __cdecl main(int argc, char** argv)
{
vdm::read_phys_t _read_phys = [&](void* addr, void* buffer, std::size_t size) -> bool
{
return vdm::read_phys(addr, buffer, size);
};
vdm::write_phys_t _write_phys = [&](void* addr, void* buffer, std::size_t size) -> bool
{
return vdm::write_phys(addr, buffer, size);
};
auto kmem_handle = nasa::kmem_ctx::get_handle();
// translation just subtracts pml4 index bit field by 255...
const auto ntoskrnl_base = util::get_kmodule_base("ntoskrnl.exe");
const auto ntoskrnl_translated = nasa::kmem_ctx::translate(ntoskrnl_base);
std::printf("[+] ntoskrnl base -> 0x%p\n", ntoskrnl_base);
std::printf("[+] ntoskrnl translated -> 0x%p\n", ntoskrnl_translated);
if (kmem_handle == INVALID_HANDLE_VALUE)
{
const auto [drv_handle, drv_key] = vdm::load_drv();
if (drv_handle == INVALID_HANDLE_VALUE)
{
std::printf("[!] invalid handle...\n");
std::getchar();
return -1;
}
vdm::vdm_ctx vdm(_read_phys, _write_phys);
nasa::kmem_ctx kmem(&vdm);
kmem_handle = kmem.get_handle();
unsigned short mz = 0u;
std::size_t bytes_handled;
// ReadProcessMemory kernel memory example...
auto result =
ReadProcessMemory(
kmem_handle,
reinterpret_cast<void*>(ntoskrnl_translated),
&mz, sizeof mz,
&bytes_handled
);
std::printf("[+] ReadProcessMemory Result -> %d, mz -> 0x%x\n", result, mz);
if (!vdm::unload_drv(drv_handle, drv_key))
{
std::printf("[!] unable to unload driver...\n");
std::getchar();
return -1;
}
}
else
{
unsigned short mz = 0u;
std::size_t bytes_handled;
// ReadProcessMemory kernel memory example...
auto result =
ReadProcessMemory(
kmem_handle,
reinterpret_cast<void*>(ntoskrnl_translated),
&mz, sizeof mz,
&bytes_handled
);
std::printf("[+] ReadProcessMemory Result -> %d, mz -> 0x%x\n", result, mz);
}
std::printf("[+] press enter to exit...\n");
std::getchar();
}

480
kmem/mem_ctx/mem_ctx.cpp

@ -0,0 +1,480 @@
#include "mem_ctx.hpp"
namespace nasa
{
mem_ctx::mem_ctx(vdm::vdm_ctx& v_ctx, std::uint32_t pid)
:
v_ctx(&v_ctx),
pid(pid),
dirbase(get_dirbase(v_ctx, pid))
{
// find an empty pml4e inside of current processes pml4...
const auto current_pml4 =
v_ctx.get_virtual(reinterpret_cast<std::uintptr_t>(
get_dirbase(v_ctx, GetCurrentProcessId())));
for (auto idx = 100u; idx > 0u; --idx)
if (!v_ctx.rkm<pml4e>(current_pml4 + (idx * sizeof pml4e)).value)
this->pml4e_index = idx;
// allocate a pdpt
this->new_pdpt.second =
reinterpret_cast<ppdpte>(
VirtualAlloc(
NULL,
PAGE_4KB,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
PAGE_IN(this->new_pdpt.second, PAGE_4KB);
// get page table entries for new pdpt
pt_entries new_pdpt_entries;
hyperspace_entries(new_pdpt_entries, new_pdpt.second);
this->new_pdpt.first = reinterpret_cast<ppdpte>(new_pdpt_entries.pt.second.pfn << 12);
// make a new pml4e that points to our new pdpt.
new_pdpt_entries.pml4.second.pfn = new_pdpt_entries.pt.second.pfn;
// set the pml4e to point to the new pdpt
set_pml4e(reinterpret_cast<::ppml4e>(get_dirbase()) + this->pml4e_index, new_pdpt_entries.pml4.second, true);
// make a new pd
this->new_pd.second =
reinterpret_cast<ppde>(
VirtualAlloc(
NULL,
PAGE_4KB,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
PAGE_IN(this->new_pd.second, PAGE_4KB);
// get paging table entries for pd
pt_entries new_pd_entries;
hyperspace_entries(new_pd_entries, this->new_pd.second);
this->new_pd.first = reinterpret_cast<ppde>(new_pd_entries.pt.second.pfn << 12);
// make a new pt
this->new_pt.second =
reinterpret_cast<ppte>(
VirtualAlloc(
NULL,
PAGE_4KB,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
PAGE_IN(this->new_pt.second, PAGE_4KB);
// get paging table entries for pt
pt_entries new_pt_entries;
hyperspace_entries(new_pt_entries, this->new_pt.second);
this->new_pt.first = reinterpret_cast<ppte>(new_pt_entries.pt.second.pfn << 12);
}
void* mem_ctx::set_page(void* addr)
{
// table entry change.
++pte_index;
if (pte_index >= 511)
{
++pde_index;
pte_index = 0;
}
if (pde_index >= 511)
{
++pdpte_index;
pde_index = 0;
}
if (pdpte_index >= 511)
pdpte_index = 0;
pdpte new_pdpte = { NULL };
new_pdpte.present = true;
new_pdpte.rw = true;
new_pdpte.pfn = reinterpret_cast<std::uintptr_t>(new_pd.first) >> 12;
new_pdpte.user_supervisor = true;
new_pdpte.accessed = true;
// set pdpte entry
*reinterpret_cast<pdpte*>(new_pdpt.second + pdpte_index) = new_pdpte;
pde new_pde = { NULL };
new_pde.present = true;
new_pde.rw = true;
new_pde.pfn = reinterpret_cast<std::uintptr_t>(new_pt.first) >> 12;
new_pde.user_supervisor = true;
new_pde.accessed = true;
// set pde entry
*reinterpret_cast<pde*>(new_pd.second + pde_index) = new_pde;
pte new_pte = { NULL };
new_pte.present = true;
new_pte.rw = true;
new_pte.pfn = reinterpret_cast<std::uintptr_t>(addr) >> 12;
new_pte.user_supervisor = true;
new_pte.accessed = true;
// set pte entry
*reinterpret_cast<pte*>(new_pt.second + pte_index) = new_pte;
// set page offset
this->page_offset = virt_addr_t{ addr }.offset;
return get_page();
}
void* mem_ctx::get_page() const
{
// builds a new address given the state of all table indexes
virt_addr_t new_addr;
new_addr.pml4_index = this->pml4e_index;
new_addr.pdpt_index = this->pdpte_index;
new_addr.pd_index = this->pde_index;
new_addr.pt_index = this->pte_index;
new_addr.offset = this->page_offset;
return new_addr.value;
}
void* mem_ctx::get_dirbase(vdm::vdm_ctx& v_ctx, std::uint32_t pid)
{
const auto peproc =
reinterpret_cast<std::uint64_t>(v_ctx.get_peprocess(pid));
const auto dirbase =
v_ctx.rkm<pte>(peproc + 0x28);
return reinterpret_cast<void*>(dirbase.pfn << 12);
}
bool mem_ctx::hyperspace_entries(pt_entries& entries, void* addr)
{
if (!addr || !dirbase)
return false;
virt_addr_t virt_addr{ addr };
entries.pml4.first = reinterpret_cast<ppml4e>(dirbase) + virt_addr.pml4_index;
entries.pml4.second = v_ctx->rkm<pml4e>(
v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(entries.pml4.first)));
if (!entries.pml4.second.value)
return false;
entries.pdpt.first = reinterpret_cast<ppdpte>(entries.pml4.second.pfn << 12) + virt_addr.pdpt_index;
entries.pdpt.second = v_ctx->rkm<pdpte>(
v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(entries.pdpt.first)));
if (!entries.pdpt.second.value)
return false;
entries.pd.first = reinterpret_cast<ppde>(entries.pdpt.second.pfn << 12) + virt_addr.pd_index;
entries.pd.second = v_ctx->rkm<pde>(
v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(entries.pd.first)));
// if its a 2mb page
if (entries.pd.second.large_page)
{
entries.pt.second.value = entries.pd.second.value;
entries.pt.first = reinterpret_cast<ppte>(entries.pd.second.value);
return true;
}
entries.pt.first = reinterpret_cast<ppte>(entries.pd.second.pfn << 12) + virt_addr.pt_index;
entries.pt.second = v_ctx->rkm<pte>(
v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(entries.pt.first)));
if (!entries.pt.second.value)
return false;
return true;
}
std::pair<ppte, pte> mem_ctx::get_pte(void* addr, bool use_hyperspace)
{
if (!dirbase || !addr)
return {};
pt_entries entries;
if ((use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)))
return { entries.pt.first, entries.pt.second };
return {};
}
void mem_ctx::set_pte(void* addr, const ::pte& pte, bool use_hyperspace)
{
if (!dirbase || !addr)
return;
if (use_hyperspace)
v_ctx->wkm(v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(addr)), pte);
else
write_phys(addr, pte);
}
std::pair<ppde, pde> mem_ctx::get_pde(void* addr, bool use_hyperspace)
{
if (!dirbase || !addr)
return {};
pt_entries entries;
if ((use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)))
return { entries.pd.first, entries.pd.second };
return {};
}
void mem_ctx::set_pde(void* addr, const ::pde& pde, bool use_hyperspace)
{
if (!this->dirbase || !addr)
return;
if (use_hyperspace)
v_ctx->wkm(v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(addr)), pde);
else
write_phys(addr, pde);
}
std::pair<ppdpte, pdpte> mem_ctx::get_pdpte(void* addr, bool use_hyperspace)
{
if (!dirbase || !addr)
return {};
pt_entries entries;
if ((use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)))
return { entries.pdpt.first, entries.pdpt.second };
return {};
}
void mem_ctx::set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace)
{
if (!this->dirbase || !addr)
return;
if (use_hyperspace)
v_ctx->wkm(v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(addr)), pdpte);
else
write_phys(addr, pdpte);
}
std::pair<ppml4e, pml4e> mem_ctx::get_pml4e(void* addr, bool use_hyperspace)
{
if (!this->dirbase || !addr)
return {};
pt_entries entries;
if ((use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)))
return { entries.pml4.first, entries.pml4.second };
return {};
}
void mem_ctx::set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace)
{
if (!this->dirbase || !addr)
return;
if (use_hyperspace)
v_ctx->wkm(v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(addr)), pml4e);
else
write_phys(addr, pml4e);
}
std::pair<void*, void*> mem_ctx::read_virtual(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size || !dirbase)
return {};
virt_addr_t virt_addr{ addr };
if (size <= PAGE_4KB - virt_addr.offset)
{
pt_entries entries;
read_phys
(
buffer,
virt_to_phys(entries, addr),
size
);
return
{
reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(buffer) + size),
reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(addr) + size)
};
}
else
{
// cut remainder
const auto [new_buffer_addr, new_addr] = read_virtual
(
buffer,
addr,
PAGE_4KB - virt_addr.offset
);
// forward work load
return read_virtual
(
new_buffer_addr,
new_addr,
size - (PAGE_4KB - virt_addr.offset)
);
}
}
std::pair<void*, void*> mem_ctx::write_virtual(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size || !dirbase)
return {};
virt_addr_t virt_addr{ addr };
if (size <= PAGE_4KB - virt_addr.offset)
{
pt_entries entries;
write_phys
(
buffer,
virt_to_phys(entries, addr),
size
);
return
{
reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(buffer) + size),
reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(addr) + size)
};
}
else
{
// cut remainder
const auto [new_buffer_addr, new_addr] = write_virtual
(
buffer,
addr,
PAGE_4KB - virt_addr.offset
);
// forward work load
return write_virtual
(
new_buffer_addr,
new_addr,
size - (PAGE_4KB - virt_addr.offset)
);
}
}
bool mem_ctx::read_phys(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size)
return false;
const auto temp_page = set_page(addr);
__try
{
memcpy(buffer, temp_page, size);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return false;
}
return true;
}
bool mem_ctx::write_phys(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size)
return false;
const auto temp_page = set_page(addr);
__try
{
memcpy(temp_page, buffer, size);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return false;
}
return true;
}
void* mem_ctx::virt_to_phys(pt_entries& entries, void* addr)
{
if (!addr || !this->dirbase)
return {};
const virt_addr_t virt_addr{ addr };
// traverse paging tables
auto pml4e = read_phys<::pml4e>(
reinterpret_cast<ppml4e>(this->dirbase) + virt_addr.pml4_index);
entries.pml4.first = reinterpret_cast<ppml4e>(this->dirbase) + virt_addr.pml4_index;
entries.pml4.second = pml4e;
if (!pml4e.value)
return NULL;
auto pdpte = read_phys<::pdpte>(
reinterpret_cast<ppdpte>(pml4e.pfn << 12) + virt_addr.pdpt_index);
entries.pdpt.first = reinterpret_cast<ppdpte>(pml4e.pfn << 12) + virt_addr.pdpt_index;
entries.pdpt.second = pdpte;
if (!pdpte.value)
return NULL;
auto pde = read_phys<::pde>(
reinterpret_cast<ppde>(pdpte.pfn << 12) + virt_addr.pd_index);
entries.pd.first = reinterpret_cast<ppde>(pdpte.pfn << 12) + virt_addr.pd_index;
entries.pd.second = pde;
if (!pde.value)
return NULL;
auto pte = read_phys<::pte>(
reinterpret_cast<ppte>(pde.pfn << 12) + virt_addr.pt_index);
entries.pt.first = reinterpret_cast<ppte>(pde.pfn << 12) + virt_addr.pt_index;
entries.pt.second = pte;
if (!pte.value)
return NULL;
return reinterpret_cast<void*>((pte.pfn << 12) + virt_addr.offset);
}
unsigned mem_ctx::get_pid() const
{
return this->pid;
}
void* mem_ctx::get_dirbase() const
{
return this->dirbase;
}
pml4e mem_ctx::operator[](std::uint16_t pml4_idx)
{
return read_phys<::pml4e>(reinterpret_cast<ppml4e>(this->dirbase) + pml4_idx);
}
pdpte mem_ctx::operator[](const std::pair<std::uint16_t, std::uint16_t>& entry_idx)
{
const auto pml4_entry = this->operator[](entry_idx.first);
return read_phys<::pdpte>(reinterpret_cast<ppdpte>(pml4_entry.pfn << 12) + entry_idx.second);
}
pde mem_ctx::operator[](const std::tuple<std::uint16_t, std::uint16_t, std::uint16_t>& entry_idx)
{
const auto pdpt_entry = this->operator[]({ std::get<0>(entry_idx), std::get<1>(entry_idx) });
return read_phys<::pde>(reinterpret_cast<ppde>(pdpt_entry.pfn << 12) + std::get<2>(entry_idx));
}
pte mem_ctx::operator[](const std::tuple<std::uint16_t, std::uint16_t, std::uint16_t, std::uint16_t>& entry_idx)
{
const auto pd_entry = this->operator[]({ std::get<0>(entry_idx), std::get<1>(entry_idx), std::get<2>(entry_idx) });
return read_phys<::pte>(reinterpret_cast<ppte>(pd_entry.pfn << 12) + std::get<3>(entry_idx));
}
}

86
kmem/mem_ctx/mem_ctx.hpp

@ -0,0 +1,86 @@
#pragma once
#include "../util/nt.hpp"
#include "../vdm_ctx/vdm_ctx.hpp"
namespace nasa
{
class mem_ctx
{
friend class pclone_ctx;
public:
mem_ctx(vdm::vdm_ctx& v_ctx, std::uint32_t pid = GetCurrentProcessId());
std::pair<ppte, pte> get_pte(void* addr, bool use_hyperspace = false);
void set_pte(void* addr, const ::pte& pte, bool use_hyperspace = false);
std::pair<ppde, pde> get_pde(void* addr, bool use_hyperspace = false);
void set_pde(void* addr, const ::pde& pde, bool use_hyperspace = false);
std::pair<ppdpte, pdpte> get_pdpte(void* addr, bool use_hyperspace = false);
void set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace = false);
std::pair<ppml4e, pml4e> get_pml4e(void* addr, bool use_hyperspace = false);
void set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace = false);
void* get_dirbase() const;
static void* get_dirbase(vdm::vdm_ctx& v_ctx, std::uint32_t pid);
bool read_phys(void* buffer, void* addr, std::size_t size);
bool write_phys(void* buffer, void* addr, std::size_t size);
template <class T>
T read_phys(void* addr)
{
T buffer;
read_phys((void*)&buffer, addr, sizeof(T));
return buffer;
}
template <class T>
void write_phys(void* addr, const T& data)
{
write_phys((void*)&data, addr, sizeof(T));
}
std::pair<void*, void*> read_virtual(void* buffer, void* addr, std::size_t size);
std::pair<void*, void*> write_virtual(void* buffer, void* addr, std::size_t size);
template <class T>
__forceinline T read_virtual(void* addr)
{
T buffer;
read_virtual((void*)&buffer, addr, sizeof(T));
return buffer;
}
template <class T>
__forceinline void write_virtual(void* addr, const T& data)
{
write_virtual((void*)&data, addr, sizeof(T));
}
void* virt_to_phys(pt_entries& entries, void* addr);
void* set_page(void* addr);
void* get_page() const;
unsigned get_pid() const;
pml4e operator[](std::uint16_t pml4_idx);
pdpte operator[](const std::pair<std::uint16_t, std::uint16_t>& entry_idx);
pde operator[](const std::tuple<std::uint16_t, std::uint16_t, std::uint16_t>& entry_idx);
pte operator[](const std::tuple<std::uint16_t, std::uint16_t, std::uint16_t, std::uint16_t>& entry_idx);
private:
bool hyperspace_entries(pt_entries& entries, void* addr);
void* dirbase;
vdm::vdm_ctx* v_ctx;
std::uint16_t pml4e_index,
pdpte_index,
pde_index,
pte_index,
page_offset;
std::pair<ppdpte, ppdpte> new_pdpt;
std::pair<ppde,ppde> new_pd;
std::pair<ppte, ppte> new_pt;
unsigned pid;
};
}

BIN
kmem/small.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

247
kmem/util/loadup.hpp

@ -0,0 +1,247 @@
/*
MIT License
Copyright (c) 2020 xerox
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <Windows.h>
#include <Winternl.h>
#include <string>
#include <fstream>
#include <filesystem>
#pragma comment(lib, "ntdll.lib")
extern "C" NTSTATUS NtLoadDriver(PUNICODE_STRING);
extern "C" NTSTATUS NtUnloadDriver(PUNICODE_STRING);
namespace driver
{
namespace util
{
__forceinline auto delete_service_entry(const std::string& service_name) -> bool
{
HKEY reg_handle;
static const std::string reg_key("System\\CurrentControlSet\\Services\\");
auto result = RegOpenKeyA(
HKEY_LOCAL_MACHINE,
reg_key.c_str(),
&reg_handle
);
return ERROR_SUCCESS == RegDeleteKeyA(reg_handle, service_name.data()) &&
ERROR_SUCCESS == RegCloseKey(reg_handle);;
}
__forceinline auto create_service_entry(const std::string& drv_path, const std::string& service_name) -> bool
{
HKEY reg_handle;
std::string reg_key("System\\CurrentControlSet\\Services\\");
reg_key += service_name;
auto result = RegCreateKeyA(
HKEY_LOCAL_MACHINE,
reg_key.c_str(),
&reg_handle
);
if (result != ERROR_SUCCESS)
return false;
std::uint8_t type_value = 1;
result = RegSetValueExA(
reg_handle,
"Type",
NULL,
REG_DWORD,
&type_value,
4u
);
if (result != ERROR_SUCCESS)
return false;
std::uint8_t error_control_value = 3;
result = RegSetValueExA(
reg_handle,
"ErrorControl",
NULL,
REG_DWORD,
&error_control_value,
4u
);
if (result != ERROR_SUCCESS)
return false;
std::uint8_t start_value = 3;
result = RegSetValueExA(
reg_handle,
"Start",
NULL,
REG_DWORD,
&start_value,
4u
);
if (result != ERROR_SUCCESS)
return false;
result = RegSetValueExA(
reg_handle,
"ImagePath",
NULL,
REG_SZ,
(std::uint8_t*) drv_path.c_str(),
drv_path.size()
);
if (result != ERROR_SUCCESS)
return false;
return ERROR_SUCCESS == RegCloseKey(reg_handle);
}
__forceinline auto enable_privilege(const std::wstring& privilege_name) -> bool
{
HANDLE token_handle = nullptr;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
return false;
LUID luid{};
if (!LookupPrivilegeValueW(nullptr, privilege_name.data(), &luid))
return false;
TOKEN_PRIVILEGES token_state{};
token_state.PrivilegeCount = 1;
token_state.Privileges[0].Luid = luid;
token_state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(token_handle, FALSE, &token_state, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr))
return false;
CloseHandle(token_handle);
return true;
}
__forceinline auto get_service_image_path(const std::string& service_name) -> std::string
{
HKEY reg_handle;
DWORD bytes_read;
char image_path[0xFF];
static const std::string reg_key("System\\CurrentControlSet\\Services\\");
auto result = RegOpenKeyA(
HKEY_LOCAL_MACHINE,
reg_key.c_str(),
&reg_handle
);
result = RegGetValueA(
reg_handle,
service_name.c_str(),
"ImagePath",
REG_SZ,
NULL,
image_path,
&bytes_read
);
RegCloseKey(reg_handle);
return std::string(image_path);
}
}
__forceinline auto load(const std::string& drv_path, const std::string& service_name) -> bool
{
if (!util::enable_privilege(L"SeLoadDriverPrivilege"))
return false;
if (!util::create_service_entry("\\??\\" +
std::filesystem::absolute(std::filesystem::path(drv_path)).string(), service_name))
return false;
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
reg_path += service_name;
ANSI_STRING driver_rep_path_cstr;
UNICODE_STRING driver_reg_path_unicode;
RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
return ERROR_SUCCESS == NtLoadDriver(&driver_reg_path_unicode);
}
__forceinline auto load(const std::vector<std::uint8_t>& drv_buffer) -> std::tuple<bool, std::string>
{
static const auto random_file_name = [](std::size_t length) -> std::string
{
static const auto randchar = []() -> char
{
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const std::size_t max_index = (sizeof(charset) - 1);
return charset[rand() % max_index];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
};
const auto service_name = random_file_name(16);
const auto file_path = std::filesystem::temp_directory_path().string() + service_name;
std::ofstream output_file(file_path.c_str(), std::ios::binary);
output_file.write((char*)drv_buffer.data(), drv_buffer.size());
output_file.close();
return { load(file_path, service_name), service_name };
}
__forceinline auto load(const std::uint8_t* buffer, const std::size_t size) -> std::tuple<bool, std::string>
{
std::vector<std::uint8_t> image(buffer, buffer + size);
return load(image);
}
__forceinline auto unload(const std::string& service_name) -> bool
{
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
reg_path += service_name;
ANSI_STRING driver_rep_path_cstr;
UNICODE_STRING driver_reg_path_unicode;
RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
const bool unload_drv = STATUS_SUCCESS == NtUnloadDriver(&driver_reg_path_unicode);
if (!unload_drv) return false;
const auto image_path = std::filesystem::temp_directory_path().string() + service_name;
const bool delete_reg = util::delete_service_entry(service_name);
return delete_reg && unload_drv;
}
}

193
kmem/util/nt.hpp

@ -0,0 +1,193 @@
#pragma once
#include <Windows.h>
#include <winternl.h>
#include <ntstatus.h>
#include <cstdint>
#include <cstddef>
#include <map>
#pragma comment(lib, "ntdll.lib")
#if _DEBUG
#define DBG_ASSERT(...) assert(__VA_ARGS__)
#define DBG_PRINT(...) printf(__VA_ARGS__)
#else
#define DBG_ASSERT(...) assert(__VA_ARGS__)
#define DBG_PRINT(...) printf(__VA_ARGS__)
#endif
#define PAGE_4KB 0x1000
#define MM_COPY_MEMORY_PHYSICAL 0x1
#define MM_COPY_MEMORY_VIRTUAL 0x2
#define PAGE_IN(addr, size) memset(addr, NULL, size)
constexpr auto SystemModuleInformation = 11;
constexpr auto SystemHandleInformation = 16;
constexpr auto SystemExtendedHandleInformation = 64;
typedef struct _RTL_PROCESS_MODULE_INFORMATION
{
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULES
{
ULONG NumberOfModules;
RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;
typedef LARGE_INTEGER PHYSICAL_ADDRESS, * PPHYSICAL_ADDRESS;
typedef struct _MM_COPY_ADDRESS {
union {
PVOID VirtualAddress;
PHYSICAL_ADDRESS PhysicalAddress;
};
} MM_COPY_ADDRESS, * PMMCOPY_ADDRESS;
using PEPROCESS = PVOID;
using PsLookupProcessByProcessId = NTSTATUS (__fastcall*)(
HANDLE ProcessId,
PEPROCESS* Process
);
using MmCopyMemory = NTSTATUS(__stdcall*)(
PVOID,
MM_COPY_ADDRESS,
SIZE_T,
ULONG,
PSIZE_T
);
using MmGetVirtualForPhysical = std::uintptr_t(__fastcall*)(
__in std::uintptr_t PhysicalAddress
);
using MmGetPhysicalAddress = std::uintptr_t(__fastcall*)(
__in std::uintptr_t BaseAddress
);
// PsGetAllocatedFullProcessImageNameEx...
using GET_PROC_NAME = std::uint32_t(*)(PEPROCESS);
typedef union _virt_addr_t
{
void* value;
struct
{
std::uint64_t offset : 12;
std::uint64_t pt_index : 9;
std::uint64_t pd_index : 9;
std::uint64_t pdpt_index : 9;
std::uint64_t pml4_index : 9;
std::uint64_t reserved : 16;
};
} virt_addr_t, *pvirt_addr_t;
static_assert(sizeof(virt_addr_t) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
typedef union _pml4e
{
std::uint64_t value;
struct
{
std::uint64_t present : 1; // Must be 1, region invalid if 0.
std::uint64_t ReadWrite : 1; // If 0, writes not allowed.
std::uint64_t user_supervisor : 1; // If 0, user-mode accesses not allowed.
std::uint64_t PageWriteThrough : 1; // Determines the memory type used to access PDPT.
std::uint64_t page_cache : 1; // Determines the memory type used to access PDPT.
std::uint64_t accessed : 1; // If 0, this entry has not been used for translation.
std::uint64_t Ignored1 : 1;
std::uint64_t large_page : 1; // Must be 0 for PML4E.
std::uint64_t Ignored2 : 4;
std::uint64_t pfn : 36; // The page frame number of the PDPT of this PML4E.
std::uint64_t Reserved : 4;
std::uint64_t Ignored3 : 11;
std::uint64_t nx : 1; // If 1, instruction fetches not allowed.
};
} pml4e, * ppml4e;
static_assert(sizeof(pml4e) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
typedef union _pdpte
{
std::uint64_t value;
struct
{
std::uint64_t present : 1; // Must be 1, region invalid if 0.
std::uint64_t rw : 1; // If 0, writes not allowed.
std::uint64_t user_supervisor : 1; // If 0, user-mode accesses not allowed.
std::uint64_t PageWriteThrough : 1; // Determines the memory type used to access PD.
std::uint64_t page_cache : 1; // Determines the memory type used to access PD.
std::uint64_t accessed : 1; // If 0, this entry has not been used for translation.
std::uint64_t Ignored1 : 1;
std::uint64_t large_page : 1; // If 1, this entry maps a 1GB page.
std::uint64_t Ignored2 : 4;
std::uint64_t pfn : 36; // The page frame number of the PD of this PDPTE.
std::uint64_t Reserved : 4;
std::uint64_t Ignored3 : 11;
std::uint64_t nx : 1; // If 1, instruction fetches not allowed.
};
} pdpte, * ppdpte;
static_assert(sizeof(pdpte) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
typedef union _pde
{
std::uint64_t value;
struct
{
std::uint64_t present : 1; // Must be 1, region invalid if 0.
std::uint64_t rw : 1; // If 0, writes not allowed.
std::uint64_t user_supervisor : 1; // If 0, user-mode accesses not allowed.