typedef union _PTE
{
// Normally, emulating PAGE_NOACCESS means turning the valid bit off in the PTE
ULONG64 value;
// Bitfield in a struct
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0. (PAGE_NOACCESS) // bit 0
ULONG64 rw : 1; // written-before // bit 1
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 page_write : 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 large_page : 1; // Large page
ULONG64 global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
ULONG64 cow : 1; // copy on write
ULONG64 prt : 1; // protetype
ULONG64 wrt : 1; // write-access
ULONG64 pfn : 36; // The page frame number of the backing physical page.
ULONG64 reserved : 4;
ULONG64 ignored3 : 7;
ULONG64 protect_key : 4; // If the PKE bit of CR4 is set, determines the protection key.
ULONG64 nx : 1; // If 1, instruction fetches not allowed.
};
} PTE, * PPTE;
auto fint_pte_base() -> uintptr_t {
auto ntoskrnl = utils::get_kernel_module("ntoskrnl.exe");
uintptr_t pte_base{ 0 };
if (ntoskrnl) {
printf("ntoskrnl base => 0x%p!", ntoskrnl);
auto sig_base = utils::pattern_scan(ntoskrnl, "\x48\xC1\xE9\x09\x48\xB8\xF8\xFF\xFF\xFF\x7F\x00\x00\x00\x48\x23\xC8\x48\xB8", "xxxxxxxxxxxxxxxxxxx");
if (sig_base)
{
pte_base = *(__int64*)(sig_base + 19);
printf("pte base found at => 0x%p!", pte_base);
}
else
{
printf("sig_base not found!");
}
}
else
{
printf("ntoskrnl not found!");
}
return pte_base;
}
auto resolve_pte_for_virtual(uintptr_t virtual_address) -> uintptr_t {
auto MiGetPteAddress = [](unsigned __int64 a1) -> unsigned __int64
{
unsigned __int64 pte_base = fint_pte_base();
return pte_base ? ((a1 >> 9) & 0x7FFFFFFFF8) + pte_base : 0;
};
return MiGetPteAddress(virtual_address);
}
NTSTATUS give_execute_access(uint32_t cid, uintptr_t virtual_address) {
PEPROCESS process = { 0 }; NTSTATUS status = STATUS_UNSUCCESSFUL;
PsLookupProcessByProcessId(HANDLE(cid), &process);
if (process != nullptr && virtual_address != 0)
{
unsigned __int64 pte_virtual = resolve_pte_for_virtual(virtual_address);
if (pte_virtual != 0)
{
printf("[+] pte_virtual => 0x%p", pte_virtual);
KAPC_STATE state = { 0 };
KeStackAttachProcess(process, &state);
unsigned __int64 bits = *(unsigned __int64*)pte_virtual;
PTE pte_new = { 0 };
pte_new.value = bits;
pte_new.nx = 0;
*(unsigned __int64*)pte_virtual = pte_new.value;
KeUnstackDetachProcess(&state);
status = STATUS_SUCCESS;
}
ObDereferenceObject(process);
}
return status;
}
NTSTATUS give_write_access(uint32_t cid, uintptr_t virtual_address) {
PEPROCESS process = { 0 }; NTSTATUS status = STATUS_UNSUCCESSFUL;
PsLookupProcessByProcessId(HANDLE(cid), &process);
if (process != nullptr && virtual_address != 0)
{
unsigned __int64 pte_virtual = resolve_pte_for_virtual(virtual_address);
if (pte_virtual != 0)
{
KAPC_STATE state = { 0 };
KeStackAttachProcess(process, &state);
unsigned __int64 bits = *(unsigned __int64*)pte_virtual;
PTE pte_new = { 0 };
pte_new.value = bits;
pte_new.wrt = 1;
*(unsigned __int64*)pte_virtual = pte_new.value;
KeUnstackDetachProcess(&state);
status = STATUS_SUCCESS;
}
ObDereferenceObject(process);
}
return status;
}