diff --git a/nasa-patch.sln b/PSKP.sln
similarity index 53%
rename from nasa-patch.sln
rename to PSKP.sln
index 2f002c6..e3cf0c2 100644
--- a/nasa-patch.sln
+++ b/PSKP.sln
@@ -3,24 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nasa-patch", "nasa-patch\nasa-patch.vcxproj", "{D5E350A6-1FFC-466E-81D7-9691D0E58002}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PSKP", "PSKP\PSKP.vcxproj", "{D5E350A6-1FFC-466E-81D7-9691D0E58002}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
Release|x64 = Release|x64
- Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {D5E350A6-1FFC-466E-81D7-9691D0E58002}.Debug|x64.ActiveCfg = Debug|x64
- {D5E350A6-1FFC-466E-81D7-9691D0E58002}.Debug|x64.Build.0 = Debug|x64
- {D5E350A6-1FFC-466E-81D7-9691D0E58002}.Debug|x86.ActiveCfg = Debug|Win32
- {D5E350A6-1FFC-466E-81D7-9691D0E58002}.Debug|x86.Build.0 = Debug|Win32
{D5E350A6-1FFC-466E-81D7-9691D0E58002}.Release|x64.ActiveCfg = Release|x64
{D5E350A6-1FFC-466E-81D7-9691D0E58002}.Release|x64.Build.0 = Release|x64
- {D5E350A6-1FFC-466E-81D7-9691D0E58002}.Release|x86.ActiveCfg = Release|Win32
- {D5E350A6-1FFC-466E-81D7-9691D0E58002}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/nasa-patch/nasa-patch.vcxproj b/PSKP/PSKP.vcxproj
similarity index 95%
rename from nasa-patch/nasa-patch.vcxproj
rename to PSKP/PSKP.vcxproj
index 25c0dae..31856b8 100644
--- a/nasa-patch/nasa-patch.vcxproj
+++ b/PSKP/PSKP.vcxproj
@@ -24,6 +24,7 @@
{d5e350a6-1ffc-466e-81d7-9691d0e58002}
nasapatch
10.0
+ PSKP
@@ -140,21 +141,23 @@
-
+
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/PSKP/PSKP.vcxproj.filters b/PSKP/PSKP.vcxproj.filters
new file mode 100644
index 0000000..793b89c
--- /dev/null
+++ b/PSKP/PSKP.vcxproj.filters
@@ -0,0 +1,64 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {efdecd69-b7b9-4d44-b106-2566baa07d86}
+
+
+ {716c3cdb-d7d0-4149-a9e7-92eca1084619}
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files\util
+
+
+ Header Files\util
+
+
+ Header Files\util
+
+
+ Header Files\vdm
+
+
+ Header Files\vdm
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/nasa-patch/nasa-patch.vcxproj.user b/PSKP/PSKP.vcxproj.user
similarity index 100%
rename from nasa-patch/nasa-patch.vcxproj.user
rename to PSKP/PSKP.vcxproj.user
diff --git a/PSKP/icon.rc b/PSKP/icon.rc
new file mode 100644
index 0000000..5856874
--- /dev/null
+++ b/PSKP/icon.rc
@@ -0,0 +1,3 @@
+// Icon Resource Definition
+#define MAIN_ICON 102
+MAIN_ICON ICON "small.ico"
\ No newline at end of file
diff --git a/PSKP/main.cpp b/PSKP/main.cpp
new file mode 100644
index 0000000..a208580
--- /dev/null
+++ b/PSKP/main.cpp
@@ -0,0 +1,44 @@
+#include
+#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(
+ 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(new_patch_page) = 0xDEAD;
+
+ std::cout << "[+] kernel MZ (before patch): " << std::hex << v_ctx.rkm(function_addr) << std::endl;
+ kernel_patch.enable();
+ std::cout << "[+] kernel MZ (patch enabled): " << std::hex << v_ctx.rkm(function_addr) << std::endl;
+ kernel_patch.disable();
+ std::cout << "[+] kernel MZ (patch disabled): " << std::hex << v_ctx.rkm(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();
+}
diff --git a/PSKP/mem_ctx/mem_ctx.cpp b/PSKP/mem_ctx/mem_ctx.cpp
new file mode 100644
index 0000000..f8c9ca7
--- /dev/null
+++ b/PSKP/mem_ctx/mem_ctx.cpp
@@ -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(
+ get_dirbase(v_ctx, GetCurrentProcessId())));
+
+ for (auto idx = 100u; idx > 0u; --idx)
+ if (!v_ctx.rkm(current_pml4 + (idx * sizeof pml4e)).value)
+ this->pml4e_index = idx;
+
+ // allocate a pdpt
+ this->new_pdpt.second =
+ reinterpret_cast(
+ 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(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(
+ 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(new_pd_entries.pt.second.pfn << 12);
+
+ // make a new pt
+ this->new_pt.second =
+ reinterpret_cast(
+ 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(new_pt_entries.pt.second.pfn << 12);
+ }
+
+ mem_ctx::~mem_ctx()
+ {
+ const auto pml4 =
+ reinterpret_cast(
+ 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(new_pd.first) >> 12;
+ new_pdpte.user_supervisor = true;
+ new_pdpte.accessed = true;
+
+ // set pdpte entry
+ *reinterpret_cast(new_pdpt.second + pdpte_index) = new_pdpte;
+
+ pde new_pde = { NULL };
+ new_pde.present = true;
+ new_pde.rw = true;
+ new_pde.pfn = reinterpret_cast(new_pt.first) >> 12;
+ new_pde.user_supervisor = true;
+ new_pde.accessed = true;
+
+ // set pde entry
+ *reinterpret_cast(new_pd.second + pde_index) = new_pde;
+
+ pte new_pte = { NULL };
+ new_pte.present = true;
+ new_pte.rw = true;
+ new_pte.pfn = reinterpret_cast(addr) >> 12;
+ new_pte.user_supervisor = true;
+ new_pte.accessed = true;
+
+ // set pte entry
+ *reinterpret_cast(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(v_ctx.get_peprocess(pid));
+
+ const auto dirbase =
+ v_ctx.rkm(peproc + 0x28);
+
+ return reinterpret_cast(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(dirbase) + virt_addr.pml4_index;
+ entries.pml4.second = v_ctx->rkm(
+ v_ctx->get_virtual(reinterpret_cast(entries.pml4.first)));
+
+ if (!entries.pml4.second.value)
+ return false;
+
+ entries.pdpt.first = reinterpret_cast(entries.pml4.second.pfn << 12) + virt_addr.pdpt_index;
+ entries.pdpt.second = v_ctx->rkm(
+ v_ctx->get_virtual(reinterpret_cast(entries.pdpt.first)));
+
+ if (!entries.pdpt.second.value)
+ return false;
+
+ entries.pd.first = reinterpret_cast(entries.pdpt.second.pfn << 12) + virt_addr.pd_index;
+ entries.pd.second = v_ctx->rkm(
+ v_ctx->get_virtual(reinterpret_cast(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(entries.pd.second.value);
+ return true;
+ }
+
+ entries.pt.first = reinterpret_cast(entries.pd.second.pfn << 12) + virt_addr.pt_index;
+ entries.pt.second = v_ctx->rkm(
+ v_ctx->get_virtual(reinterpret_cast(entries.pt.first)));
+
+ if (!entries.pt.second.value)
+ return false;
+
+ return true;
+ }
+
+ auto mem_ctx::get_pte(void* addr, bool use_hyperspace) -> std::pair
+ {
+ 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(addr)), pte);
+ else
+ write_phys(addr, pte);
+ }
+
+ auto mem_ctx::get_pde(void* addr, bool use_hyperspace) -> std::pair
+ {
+ 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(addr)), pde);
+ else
+ write_phys(addr, pde);
+ }
+
+ auto mem_ctx::get_pdpte(void* addr, bool use_hyperspace) -> std::pair
+ {
+ 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(addr)), pdpte);
+ else
+ write_phys(addr, pdpte);
+ }
+
+ auto mem_ctx::get_pml4e(void* addr, bool use_hyperspace) -> std::pair
+ {
+ 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(addr)), pml4e);
+ else
+ write_phys(addr, pml4e);
+ }
+
+ auto mem_ctx::read_virtual(void* buffer, void* addr, std::size_t size) -> std::pair
+ {
+ 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(reinterpret_cast(buffer) + size),
+ reinterpret_cast(reinterpret_cast(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
+ {
+ 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(reinterpret_cast(buffer) + size),
+ reinterpret_cast(reinterpret_cast(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(this->dirbase) + virt_addr.pml4_index);
+
+ entries.pml4.first = reinterpret_cast(this->dirbase) + virt_addr.pml4_index;
+ entries.pml4.second = pml4e;
+
+ if (!pml4e.value)
+ return NULL;
+
+ auto pdpte = read_phys<::pdpte>(
+ reinterpret_cast(pml4e.pfn << 12) + virt_addr.pdpt_index);
+
+ entries.pdpt.first = reinterpret_cast(pml4e.pfn << 12) + virt_addr.pdpt_index;
+ entries.pdpt.second = pdpte;
+
+ if (!pdpte.value)
+ return NULL;
+
+ auto pde = read_phys<::pde>(
+ reinterpret_cast(pdpte.pfn << 12) + virt_addr.pd_index);
+
+ entries.pd.first = reinterpret_cast(pdpte.pfn << 12) + virt_addr.pd_index;
+ entries.pd.second = pde;
+
+ if (!pde.value)
+ return NULL;
+
+ auto pte = read_phys<::pte>(
+ reinterpret_cast(pde.pfn << 12) + virt_addr.pt_index);
+
+ entries.pt.first = reinterpret_cast(pde.pfn << 12) + virt_addr.pt_index;
+ entries.pt.second = pte;
+
+ if (!pte.value)
+ return NULL;
+
+ return reinterpret_cast((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(this->dirbase) + pml4_idx);
+ }
+
+ pdpte mem_ctx::operator[](const std::pair& entry_idx)
+ {
+ const auto pml4_entry = this->operator[](entry_idx.first);
+ return read_phys<::pdpte>(reinterpret_cast(pml4_entry.pfn << 12) + entry_idx.second);
+ }
+
+ pde mem_ctx::operator[](const std::tuple& entry_idx)
+ {
+ const auto pdpt_entry = this->operator[]({ std::get<0>(entry_idx), std::get<1>(entry_idx) });
+ return read_phys<::pde>(reinterpret_cast(pdpt_entry.pfn << 12) + std::get<2>(entry_idx));
+ }
+
+ pte mem_ctx::operator[](const std::tuple& 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(pd_entry.pfn << 12) + std::get<3>(entry_idx));
+ }
+}
\ No newline at end of file
diff --git a/PSKP/mem_ctx/mem_ctx.hpp b/PSKP/mem_ctx/mem_ctx.hpp
new file mode 100644
index 0000000..89c2b2c
--- /dev/null
+++ b/PSKP/mem_ctx/mem_ctx.hpp
@@ -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;
+ void set_pte(void* addr, const ::pte& pte, bool use_hyperspace = false);
+
+ auto get_pde(void* addr, bool use_hyperspace = false) -> std::pair;
+ void set_pde(void* addr, const ::pde& pde, bool use_hyperspace = false);
+
+ auto get_pdpte(void* addr, bool use_hyperspace = false) -> std::pair;
+ void set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace = false);
+
+ auto get_pml4e(void* addr, bool use_hyperspace = false) -> std::pair;
+ 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
+ __forceinline T read_phys(void* addr)
+ {
+ T buffer;
+ read_phys((void*)&buffer, addr, sizeof(T));
+ return buffer;
+ }
+
+ template
+ __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;
+ auto write_virtual(void* buffer, void* addr, std::size_t size) -> std::pair;
+
+ template
+ __forceinline T read_virtual(void* addr)
+ {
+ T buffer;
+ read_virtual((void*)&buffer, addr, sizeof(T));
+ return buffer;
+ }
+
+ template
+ __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& entry_idx);
+ pde operator[](const std::tuple& entry_idx);
+ pte operator[](const std::tuple& 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 new_pdpt;
+ std::pair new_pd;
+ std::pair new_pt;
+ unsigned pid;
+ };
+}
\ No newline at end of file
diff --git a/nasa-patch/patch_ctx/patch_ctx.cpp b/PSKP/patch_ctx/patch_ctx.cpp
similarity index 62%
rename from nasa-patch/patch_ctx/patch_ctx.cpp
rename to PSKP/patch_ctx/patch_ctx.cpp
index c9d82b9..029bd3d 100644
--- a/nasa-patch/patch_ctx/patch_ctx.cpp
+++ b/PSKP/patch_ctx/patch_ctx.cpp
@@ -9,12 +9,10 @@ namespace nasa
void* patch_ctx::patch(void* kernel_addr)
{
- if (!kernel_addr)
- return {};
-
virt_addr_t kernel_addr_t{ kernel_addr };
pt_entries kernel_entries;
- if (!mem_ctx->hyperspace_entries(kernel_entries, kernel_addr))
+
+ if (!mem_ctx->virt_to_phys(kernel_entries, kernel_addr))
return {};
const auto [new_pdpt_phys, new_pdpt_virt] = make_pdpt(kernel_entries, kernel_addr);
@@ -24,9 +22,11 @@ namespace nasa
// link pdpte to pd
(reinterpret_cast(new_pdpt_virt) + kernel_addr_t.pdpt_index)->pfn = reinterpret_cast(new_pd_phys) >> 12;
- if (kernel_entries.pd.second.page_size)
+ if (kernel_entries.pd.second.large_page)
+ {
// link pde to new page if its 2mb
(reinterpret_cast(new_pd_virt) + kernel_addr_t.pd_index)->pfn = reinterpret_cast(new_page_phys) >> 12;
+ }
else
{
// link pde to pt
@@ -46,145 +46,118 @@ namespace nasa
return reinterpret_cast((std::uintptr_t)new_page_virt + kernel_addr_t.offset);
}
- std::pair patch_ctx::make_pdpt(const pt_entries& kernel_entries, void* kernel_addr)
+ auto patch_ctx::make_pdpt(const pt_entries& kernel_entries, void* kernel_addr) -> std::pair
{
- if (!kernel_addr)
- return {};
-
virt_addr_t kernel_addr_t{ kernel_addr };
const auto pdpt = reinterpret_cast(
mem_ctx->set_page(reinterpret_cast(
kernel_entries.pml4.second.pfn << 12)));
const auto new_pdpt =
- reinterpret_cast(VirtualAlloc(
- NULL,
- 0x1000,
- MEM_COMMIT | MEM_RESERVE,
- PAGE_READWRITE
- ));
- memset(new_pdpt, NULL, 0x1000);
-
- //
+ reinterpret_cast(
+ VirtualAlloc(
+ NULL,
+ PAGE_4KB,
+ MEM_COMMIT | MEM_RESERVE,
+ PAGE_READWRITE
+ ));
+
+ PAGE_IN(new_pdpt, PAGE_4KB);
// copy over pdpte's
- //
for (auto idx = 0u; idx < 512; ++idx)
- *(pdpte*)(new_pdpt + idx) = *(pdpte*)(pdpt + idx);
+ new_pdpt[idx] = pdpt[idx];
- //
// get physical address of new pdpt
- //
pt_entries new_pdpt_entries;
const auto physical_addr =
- mem_ctx->virt_to_phys(
- new_pdpt_entries,
- new_pdpt
- );
+ mem_ctx->virt_to_phys(new_pdpt_entries, new_pdpt);
return { physical_addr, new_pdpt };
}
- std::pair patch_ctx::make_pd(const pt_entries& kernel_entries, void* kernel_addr)
+ auto patch_ctx::make_pd(const pt_entries& kernel_entries, void* kernel_addr) -> std::pair
{
- if (!kernel_addr)
- return {};
-
virt_addr_t kernel_addr_t{ kernel_addr };
- const auto new_pd = reinterpret_cast(
- VirtualAlloc(
- NULL,
- 0x1000,
- MEM_COMMIT | MEM_RESERVE,
- PAGE_READWRITE
- ));
- memset(new_pd, NULL, 0x1000);
-
+ const auto new_pd =
+ reinterpret_cast(
+ VirtualAlloc(
+ NULL,
+ PAGE_4KB,
+ MEM_COMMIT | MEM_RESERVE,
+ PAGE_READWRITE
+ ));
+
+ PAGE_IN(new_pd, PAGE_4KB);
const auto pd = reinterpret_cast(
mem_ctx->set_page(
reinterpret_cast(
kernel_entries.pdpt.second.pfn << 12)));
- //
// copy over pde's
- //
for (auto idx = 0u; idx < 512; ++idx)
- *(::pde*)(new_pd + idx) = *(::pde*)(pd + idx);
+ new_pd[idx] = pd[idx];
//
// get physical address of new pd
//
pt_entries pd_entries;
const auto physical_addr =
- mem_ctx->virt_to_phys(
- pd_entries,
- new_pd
- );
+ mem_ctx->virt_to_phys(pd_entries, new_pd);
return { physical_addr, new_pd };
}
- std::pair patch_ctx::make_pt(const pt_entries& kernel_entries, void* kernel_addr)
+ auto patch_ctx::make_pt(const pt_entries& kernel_entries, void* kernel_addr) -> std::pair
{
- if (!kernel_addr || kernel_entries.pd.second.page_size) // if this address is a 2mb mapping.
+ // if this address is a 2mb mapping.
+ if (!kernel_addr || kernel_entries.pd.second.large_page)
return {};
virt_addr_t kernel_addr_t{ kernel_addr };
- const auto new_pt = reinterpret_cast(
- VirtualAlloc(
- NULL,
- 0x1000,
- MEM_COMMIT | MEM_RESERVE,
- PAGE_READWRITE
- ));
- memset(new_pt, NULL, 0x1000);
-
- const auto pt = reinterpret_cast(
+ const auto new_pt =
+ reinterpret_cast(
+ VirtualAlloc(
+ NULL,
+ PAGE_4KB,
+ MEM_COMMIT | MEM_RESERVE,
+ PAGE_READWRITE
+ ));
+
+ PAGE_IN(new_pt, PAGE_4KB);
+ const auto pt = reinterpret_cast(
mem_ctx->set_page(
reinterpret_cast(
kernel_entries.pd.second.pfn << 12)));
- //
// copy over pte's
- //
for (auto idx = 0u; idx < 512; ++idx)
- *(::pde*)(new_pt + idx) = *(::pde*)(pt + idx);
+ new_pt[idx] = pt[idx];
- //
// get physical address of new pt
- //
pt_entries entries;
const auto physical_addr =
- mem_ctx->virt_to_phys(
- entries,
- new_pt
- );
+ mem_ctx->virt_to_phys(entries, new_pt);
return { physical_addr, new_pt };
}
- std::pair patch_ctx::make_page(const pt_entries& kernel_entries, void* kernel_addr)
+ auto patch_ctx::make_page(const pt_entries& kernel_entries, void* kernel_addr) -> std::pair
{
- if (!kernel_addr)
- return {};
-
virt_addr_t kernel_addr_t{ kernel_addr };
- //
// if its a 2mb page
- //
- if (kernel_entries.pd.second.page_size)
+ if (kernel_entries.pd.second.large_page)
{
- const auto new_page = VirtualAlloc(
- NULL,
- 0x1000 * 512 * 2, // 4mb
- MEM_COMMIT | MEM_RESERVE,
- PAGE_READWRITE
- );
- memset(new_page, NULL, 512 * 0x1000); // zero 2mb
-
- //
+ const auto new_page =
+ VirtualAlloc(
+ NULL,
+ PAGE_4KB * 512 * 2, // 4mb
+ MEM_COMMIT | MEM_RESERVE,
+ PAGE_READWRITE
+ );
+
+ PAGE_IN(new_page, PAGE_4KB * 512);
// copy 2mb one page at a time.
- //
for (auto idx = 0u; idx < 512; ++idx)
{
const auto old_page = mem_ctx->set_page(reinterpret_cast((kernel_entries.pt.second.pfn << 12) + (idx * 0x1000)));
@@ -197,26 +170,25 @@ namespace nasa
}
else // 1kb
{
- const auto new_page = VirtualAlloc(
- NULL,
- 0x1000,
- MEM_COMMIT | MEM_RESERVE,
- PAGE_READWRITE
- );
- memset(new_page, NULL, 0x1000);
+ const auto new_page =
+ VirtualAlloc(
+ NULL,
+ PAGE_4KB,
+ MEM_COMMIT | MEM_RESERVE,
+ PAGE_READWRITE
+ );
+ PAGE_IN(new_page, PAGE_4KB);
const auto old_page =
mem_ctx->set_page(
reinterpret_cast(
kernel_entries.pt.second.pfn << 12));
- memcpy(new_page, old_page, 0x1000);
+ memcpy(new_page, old_page, PAGE_4KB);
pt_entries new_page_entries;
const auto new_page_phys =
mem_ctx->virt_to_phys(
- new_page_entries,
- new_page
- );
+ new_page_entries, new_page);
return { new_page_phys, new_page };
}
diff --git a/PSKP/patch_ctx/patch_ctx.hpp b/PSKP/patch_ctx/patch_ctx.hpp
new file mode 100644
index 0000000..19a038e
--- /dev/null
+++ b/PSKP/patch_ctx/patch_ctx.hpp
@@ -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;
+ auto make_pd(const pt_entries& kernel_entries, void* kernel_addr)->std::pair;
+ auto make_pt(const pt_entries& kernel_entries, void* kernel_addr)->std::pair;
+ auto make_page(const pt_entries& kernel_entries, void* kernel_addr)->std::pair;
+
+ mem_ctx* mem_ctx;
+ pt_entries new_entries;
+ pml4e new_pml4e;
+ pml4e old_pml4e;
+ void* kernel_addr;
+ ppml4e mapped_pml4e;
+ };
+}
\ No newline at end of file
diff --git a/PSKP/small.ico b/PSKP/small.ico
new file mode 100644
index 0000000..b00b875
Binary files /dev/null and b/PSKP/small.ico differ
diff --git a/nasa-patch/loadup.hpp b/PSKP/util/loadup.hpp
similarity index 61%
rename from nasa-patch/loadup.hpp
rename to PSKP/util/loadup.hpp
index 179538f..123d5c8 100644
--- a/nasa-patch/loadup.hpp
+++ b/PSKP/util/loadup.hpp
@@ -29,17 +29,16 @@
#include
#include
#include
-#include
#pragma comment(lib, "ntdll.lib")
-using nt_load_driver_t = NTSTATUS(__fastcall*)(PUNICODE_STRING);
-using nt_unload_driver_t = NTSTATUS(__fastcall*)(PUNICODE_STRING);
+extern "C" NTSTATUS NtLoadDriver(PUNICODE_STRING);
+extern "C" NTSTATUS NtUnloadDriver(PUNICODE_STRING);
namespace driver
{
namespace util
{
- inline bool delete_service_entry(const std::string& service_name)
+ __forceinline auto delete_service_entry(const std::string& service_name) -> bool
{
HKEY reg_handle;
static const std::string reg_key("System\\CurrentControlSet\\Services\\");
@@ -50,10 +49,11 @@ namespace driver
®_handle
);
- return ERROR_SUCCESS == RegDeleteKeyA(reg_handle, service_name.data()) && ERROR_SUCCESS == RegCloseKey(reg_handle);
+ return ERROR_SUCCESS == RegDeleteKeyA(reg_handle, service_name.data()) &&
+ ERROR_SUCCESS == RegCloseKey(reg_handle);;
}
- inline bool create_service_entry(const std::string& drv_path, const std::string& service_name)
+ __forceinline auto create_service_entry(const std::string& drv_path, const std::string& service_name) -> bool
{
HKEY reg_handle;
std::string reg_key("System\\CurrentControlSet\\Services\\");
@@ -68,10 +68,7 @@ namespace driver
if (result != ERROR_SUCCESS)
return false;
- //
- // set type to 1 (kernel)
- //
- constexpr std::uint8_t type_value = 1;
+ std::uint8_t type_value = 1;
result = RegSetValueExA(
reg_handle,
"Type",
@@ -84,10 +81,7 @@ namespace driver
if (result != ERROR_SUCCESS)
return false;
- //
- // set error control to 3
- //
- constexpr std::uint8_t error_control_value = 3;
+ std::uint8_t error_control_value = 3;
result = RegSetValueExA(
reg_handle,
"ErrorControl",
@@ -100,10 +94,7 @@ namespace driver
if (result != ERROR_SUCCESS)
return false;
- //
- // set start to 3
- //
- constexpr std::uint8_t start_value = 3;
+ std::uint8_t start_value = 3;
result = RegSetValueExA(
reg_handle,
"Start",
@@ -116,9 +107,6 @@ namespace driver
if (result != ERROR_SUCCESS)
return false;
- //
- // set image path to the driver on disk
- //
result = RegSetValueExA(
reg_handle,
"ImagePath",
@@ -134,8 +122,7 @@ namespace driver
return ERROR_SUCCESS == RegCloseKey(reg_handle);
}
- // this function was coded by paracord: https://githacks.org/snippets/4#L94
- inline bool enable_privilege(const std::wstring& privilege_name)
+ __forceinline auto enable_privilege(const std::wstring& privilege_name) -> bool
{
HANDLE token_handle = nullptr;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
@@ -157,7 +144,7 @@ namespace driver
return true;
}
- inline std::string get_service_image_path(const std::string& service_name)
+ __forceinline auto get_service_image_path(const std::string& service_name) -> std::string
{
HKEY reg_handle;
DWORD bytes_read;
@@ -185,36 +172,27 @@ namespace driver
}
}
- inline bool load(const std::string& drv_path, const std::string& service_name)
+ __forceinline auto load(const std::string& drv_path, const std::string& service_name) -> bool
{
if (!util::enable_privilege(L"SeLoadDriverPrivilege"))
return false;
- if (!util::create_service_entry("\\??\\" + std::filesystem::absolute(std::filesystem::path(drv_path)).string(), service_name))
+ if (!util::create_service_entry("\\??\\" +
+ std::filesystem::absolute(std::filesystem::path(drv_path)).string(), service_name))
return false;
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
reg_path += service_name;
- static const auto lp_nt_load_drv =
- ::GetProcAddress(
- GetModuleHandleA("ntdll.dll"),
- "NtLoadDriver"
- );
-
- if (lp_nt_load_drv)
- {
- ANSI_STRING driver_rep_path_cstr;
- UNICODE_STRING driver_reg_path_unicode;
+ ANSI_STRING driver_rep_path_cstr;
+ UNICODE_STRING driver_reg_path_unicode;
- RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
- RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
- return ERROR_SUCCESS == reinterpret_cast(lp_nt_load_drv)(&driver_reg_path_unicode);
- }
- return false;
+ RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
+ RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
+ return ERROR_SUCCESS == NtLoadDriver(&driver_reg_path_unicode);
}
- inline std::tuple load(const std::vector& drv_buffer)
+ __forceinline auto load(const std::vector& drv_buffer) -> std::tuple
{
static const auto random_file_name = [](std::size_t length) -> std::string
{
@@ -234,68 +212,45 @@ namespace driver
const auto service_name = random_file_name(16);
const auto file_path = std::filesystem::temp_directory_path().string() + service_name;
+ std::ofstream output_file(file_path.c_str(), std::ios::binary);
+
+ output_file.write((char*)drv_buffer.data(), drv_buffer.size());
+ output_file.close();
- const auto h_file = CreateFileA(
- file_path.data(),
- GENERIC_ALL,
- NULL, NULL,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL
- );
-
- DWORD bytes_written;
- WriteFile(
- h_file,
- drv_buffer.data(),
- drv_buffer.size(),
- &bytes_written,
- NULL
- );
-
- CloseHandle(h_file);
return { load(file_path, service_name), service_name };
}
- inline std::tuple load(const std::uint8_t* buffer, const std::size_t size)
+ __forceinline auto load(const std::uint8_t* buffer, const std::size_t size) -> std::tuple
{
std::vector image(buffer, buffer + size);
return load(image);
}
- inline bool unload(const std::string& service_name)
+ __forceinline auto unload(const std::string& service_name) -> bool
{
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
reg_path += service_name;
- static const auto lp_nt_unload_drv =
- ::GetProcAddress(
- GetModuleHandleA("ntdll.dll"),
- "NtUnloadDriver"
- );
-
- if (lp_nt_unload_drv)
- {
- ANSI_STRING driver_rep_path_cstr;
- UNICODE_STRING driver_reg_path_unicode;
+ ANSI_STRING driver_rep_path_cstr;
+ UNICODE_STRING driver_reg_path_unicode;
- RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
- RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
+ RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
+ RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
- const bool unload_drv = !reinterpret_cast(lp_nt_unload_drv)(&driver_reg_path_unicode);
- const auto image_path = util::get_service_image_path(service_name);
- const bool delete_reg = util::delete_service_entry(service_name);
+ const bool unload_drv = STATUS_SUCCESS == NtUnloadDriver(&driver_reg_path_unicode);
+ const auto image_path = std::filesystem::temp_directory_path().string() + service_name;
+ const bool delete_reg = util::delete_service_entry(service_name);
- try
- {
- const bool delete_drv = std::filesystem::remove(image_path);
- } catch(std::exception& e)
- {
- std::cerr << "[!] failed to delete image: " << e.what() << std::endl;
- }
-
- return unload_drv && delete_reg;
+ // sometimes you cannot delete the driver off disk because there are still handles open
+ // to the driver, this means the driver is still loaded into the kernel...
+ try
+ {
+ std::filesystem::remove(image_path);
+ }
+ catch (std::exception& e)
+ {
+ return false;
}
- return false;
+ return delete_reg && unload_drv;
}
}
\ No newline at end of file
diff --git a/PSKP/util/nt.hpp b/PSKP/util/nt.hpp
new file mode 100644
index 0000000..3a4c26e
--- /dev/null
+++ b/PSKP/util/nt.hpp
@@ -0,0 +1,190 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include