|
|
|
@ -2,20 +2,25 @@
|
|
|
|
|
|
|
|
|
|
namespace nasa
|
|
|
|
|
{
|
|
|
|
|
mem_ctx::mem_ctx(vdm::vdm_ctx& v_ctx, DWORD pid)
|
|
|
|
|
mem_ctx::mem_ctx(vdm::vdm_ctx* v_ctx, std::uint32_t pid)
|
|
|
|
|
:
|
|
|
|
|
v_ctx(&v_ctx),
|
|
|
|
|
dirbase(get_dirbase(v_ctx, 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())));
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
if (!v_ctx->rkm<pml4e>(current_pml4 + (idx * sizeof pml4e)).present)
|
|
|
|
|
{
|
|
|
|
|
this->pml4e_index = idx;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// allocate a pdpt
|
|
|
|
|
this->new_pdpt.second =
|
|
|
|
@ -31,13 +36,17 @@ namespace nasa
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
set_pml4e(reinterpret_cast<::ppml4e>(this->dirbase) +
|
|
|
|
|
this->pml4e_index, new_pdpt_entries.pml4.second, true);
|
|
|
|
|
|
|
|
|
|
// make a new pd
|
|
|
|
|
this->new_pd.second =
|
|
|
|
@ -54,7 +63,10 @@ namespace nasa
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
|
|
this->new_pd.first =
|
|
|
|
|
reinterpret_cast<ppde>(
|
|
|
|
|
new_pd_entries.pt.second.pfn << 12);
|
|
|
|
|
|
|
|
|
|
// make a new pt
|
|
|
|
|
this->new_pt.second =
|
|
|
|
@ -71,42 +83,42 @@ namespace nasa
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
|
|
this->new_pt.first =
|
|
|
|
|
reinterpret_cast<ppte>(
|
|
|
|
|
new_pt_entries.pt.second.pfn << 12);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mem_ctx::~mem_ctx()
|
|
|
|
|
{
|
|
|
|
|
set_pml4e(reinterpret_cast<::ppml4e>(get_dirbase()) + this->pml4e_index, pml4e{NULL});
|
|
|
|
|
while (!SwitchToThread());
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
++pte_index;
|
|
|
|
|
if (pte_index >= 511)
|
|
|
|
|
{
|
|
|
|
|
++pde_index;
|
|
|
|
|
pte_index = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pde_index >= 511)
|
|
|
|
|
{
|
|
|
|
|
++pdpte_index;
|
|
|
|
|
pde_index = 0;
|
|
|
|
|
}
|
|
|
|
|
++pde_index;
|
|
|
|
|
pte_index = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pdpte_index >= 511)
|
|
|
|
|
pdpte_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;
|
|
|
|
@ -116,7 +128,6 @@ namespace nasa
|
|
|
|
|
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;
|
|
|
|
@ -126,7 +137,6 @@ namespace nasa
|
|
|
|
|
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;
|
|
|
|
@ -145,18 +155,39 @@ namespace nasa
|
|
|
|
|
new_addr.pd_index = this->pde_index;
|
|
|
|
|
new_addr.pt_index = this->pte_index;
|
|
|
|
|
new_addr.offset = this->page_offset;
|
|
|
|
|
|
|
|
|
|
// handle TLB issues, the TLB might need to be flushed for this entry...
|
|
|
|
|
__try
|
|
|
|
|
{
|
|
|
|
|
*(std::uint8_t*)new_addr.value = *(std::uint8_t*)new_addr.value;
|
|
|
|
|
return new_addr.value;
|
|
|
|
|
}
|
|
|
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
|
{
|
|
|
|
|
// try again to access the page...
|
|
|
|
|
__try
|
|
|
|
|
{
|
|
|
|
|
*(std::uint8_t*)new_addr.value = *(std::uint8_t*)new_addr.value;
|
|
|
|
|
return new_addr.value;
|
|
|
|
|
}
|
|
|
|
|
// try one last time by yeilding execution...
|
|
|
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
|
{
|
|
|
|
|
while (!SwitchToThread())
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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));
|
|
|
|
|
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);
|
|
|
|
|
return reinterpret_cast<void*>(
|
|
|
|
|
v_ctx.rkm<pte>(peproc + 0x28).pfn << 12);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool mem_ctx::hyperspace_entries(pt_entries& entries, void* addr)
|
|
|
|
@ -201,95 +232,106 @@ namespace nasa
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<ppte, pte> mem_ctx::get_pte(void* addr, bool use_hyperspace)
|
|
|
|
|
auto mem_ctx::get_pte(void* addr, bool use_hyperspace) -> std::pair<ppte, pte>
|
|
|
|
|
{
|
|
|
|
|
if (!dirbase || !addr)
|
|
|
|
|
return {};
|
|
|
|
|
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 {};
|
|
|
|
|
|
|
|
|
|
return { {}, {} };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mem_ctx::set_pte(void* addr, const ::pte& pte, bool use_hyperspace)
|
|
|
|
|
bool mem_ctx::set_pte(void* addr, const ::pte& pte, bool use_hyperspace)
|
|
|
|
|
{
|
|
|
|
|
if (!dirbase || !addr)
|
|
|
|
|
return;
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (use_hyperspace)
|
|
|
|
|
v_ctx->wkm(v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(addr)), pte);
|
|
|
|
|
else
|
|
|
|
|
write_phys(addr, pte);
|
|
|
|
|
return v_ctx->wkm(
|
|
|
|
|
v_ctx->get_virtual(
|
|
|
|
|
reinterpret_cast<std::uintptr_t>(addr)), pte);
|
|
|
|
|
|
|
|
|
|
return write_phys(addr, pte);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<ppde, pde> mem_ctx::get_pde(void* addr, bool use_hyperspace)
|
|
|
|
|
auto mem_ctx::get_pde(void* addr, bool use_hyperspace) -> std::pair<ppde, pde>
|
|
|
|
|
{
|
|
|
|
|
if (!dirbase || !addr)
|
|
|
|
|
return {};
|
|
|
|
|
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 {};
|
|
|
|
|
return { {}, {} };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mem_ctx::set_pde(void* addr, const ::pde& pde, bool use_hyperspace)
|
|
|
|
|
bool mem_ctx::set_pde(void* addr, const ::pde& pde, bool use_hyperspace)
|
|
|
|
|
{
|
|
|
|
|
if (!this->dirbase || !addr)
|
|
|
|
|
return;
|
|
|
|
|
if (!dirbase || !addr)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (use_hyperspace)
|
|
|
|
|
v_ctx->wkm(v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(addr)), pde);
|
|
|
|
|
else
|
|
|
|
|
write_phys(addr, pde);
|
|
|
|
|
return v_ctx->wkm(
|
|
|
|
|
v_ctx->get_virtual(
|
|
|
|
|
reinterpret_cast<std::uintptr_t>(addr)), pde);
|
|
|
|
|
|
|
|
|
|
return write_phys(addr, pde);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<ppdpte, pdpte> mem_ctx::get_pdpte(void* addr, bool use_hyperspace)
|
|
|
|
|
auto mem_ctx::get_pdpte(void* addr, bool use_hyperspace) -> std::pair<ppdpte, pdpte>
|
|
|
|
|
{
|
|
|
|
|
if (!dirbase || !addr)
|
|
|
|
|
return {};
|
|
|
|
|
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 {};
|
|
|
|
|
|
|
|
|
|
return { {}, {} };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mem_ctx::set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace)
|
|
|
|
|
bool mem_ctx::set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace)
|
|
|
|
|
{
|
|
|
|
|
if (!this->dirbase || !addr)
|
|
|
|
|
return;
|
|
|
|
|
if (!dirbase || !addr)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (use_hyperspace)
|
|
|
|
|
v_ctx->wkm(v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(addr)), pdpte);
|
|
|
|
|
else
|
|
|
|
|
write_phys(addr, pdpte);
|
|
|
|
|
return v_ctx->wkm(
|
|
|
|
|
v_ctx->get_virtual(
|
|
|
|
|
reinterpret_cast<std::uintptr_t>(addr)), pdpte);
|
|
|
|
|
|
|
|
|
|
return write_phys(addr, pdpte);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<ppml4e, pml4e> mem_ctx::get_pml4e(void* addr, bool use_hyperspace)
|
|
|
|
|
auto mem_ctx::get_pml4e(void* addr, bool use_hyperspace) -> std::pair<ppml4e, pml4e>
|
|
|
|
|
{
|
|
|
|
|
if (!this->dirbase || !addr)
|
|
|
|
|
return {};
|
|
|
|
|
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 {};
|
|
|
|
|
|
|
|
|
|
return { {}, {} };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mem_ctx::set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace)
|
|
|
|
|
bool mem_ctx::set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace)
|
|
|
|
|
{
|
|
|
|
|
if (!this->dirbase || !addr)
|
|
|
|
|
return;
|
|
|
|
|
if (!dirbase || !addr)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (use_hyperspace)
|
|
|
|
|
v_ctx->wkm(v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(addr)), pml4e);
|
|
|
|
|
else
|
|
|
|
|
write_phys(addr, pml4e);
|
|
|
|
|
return v_ctx->wkm(
|
|
|
|
|
v_ctx->get_virtual(
|
|
|
|
|
reinterpret_cast<std::uintptr_t>(addr)), pml4e);
|
|
|
|
|
|
|
|
|
|
return write_phys(addr, pml4e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<void*, void*> mem_ctx::read_virtual(void* buffer, void* addr, std::size_t size)
|
|
|
|
|
auto mem_ctx::read_virtual(void* buffer, void* addr, std::size_t size) -> std::pair<void*, void*>
|
|
|
|
|
{
|
|
|
|
|
if (!buffer || !addr || !size || !dirbase)
|
|
|
|
|
return {};
|
|
|
|
@ -331,7 +373,7 @@ namespace nasa
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<void*, void*> mem_ctx::write_virtual(void* buffer, void* addr, std::size_t size)
|
|
|
|
|
auto mem_ctx::write_virtual(void* buffer, void* addr, std::size_t size) -> std::pair<void*, void*>
|
|
|
|
|
{
|
|
|
|
|
if (!buffer || !addr || !size || !dirbase)
|
|
|
|
|
return {};
|
|
|
|
@ -373,10 +415,10 @@ namespace nasa
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mem_ctx::read_phys(void* buffer, void* addr, std::size_t size)
|
|
|
|
|
bool mem_ctx::read_phys(void* buffer, void* addr, std::size_t size)
|
|
|
|
|
{
|
|
|
|
|
if (!buffer || !addr || !size)
|
|
|
|
|
return;
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const auto temp_page = set_page(addr);
|
|
|
|
|
__try
|
|
|
|
@ -384,13 +426,16 @@ namespace nasa
|
|
|
|
|
memcpy(buffer, temp_page, size);
|
|
|
|
|
}
|
|
|
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
|
{}
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mem_ctx::write_phys(void* buffer, void* addr, std::size_t size)
|
|
|
|
|
bool mem_ctx::write_phys(void* buffer, void* addr, std::size_t size)
|
|
|
|
|
{
|
|
|
|
|
if (!buffer || !addr || !size)
|
|
|
|
|
return;
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const auto temp_page = set_page(addr);
|
|
|
|
|
__try
|
|
|
|
@ -398,12 +443,15 @@ namespace nasa
|
|
|
|
|
memcpy(temp_page, buffer, size);
|
|
|
|
|
}
|
|
|
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
|
{}
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void* mem_ctx::virt_to_phys(pt_entries& entries, void* addr)
|
|
|
|
|
{
|
|
|
|
|
if (!addr || !this->dirbase)
|
|
|
|
|
if (!addr || !dirbase)
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
const virt_addr_t virt_addr{ addr };
|
|
|
|
@ -447,37 +495,4 @@ namespace nasa
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
}
|